diff options
Diffstat (limited to 'compiler')
160 files changed, 2453 insertions, 1178 deletions
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 9253b7e6891..10d7fa1db60 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bitflags = "1.2.1" +memchr = "2.5.0" rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index da05b09b37d..d021bea5eca 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -227,8 +227,30 @@ pub struct FormatOptions { pub alignment: Option<FormatAlignment>, /// The fill character. E.g. the `.` in `{:.>10}`. pub fill: Option<char>, - /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags. - pub flags: u32, + /// The `+` or `-` flag. + pub sign: Option<FormatSign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. E.g. the `0` in `{:02x}`. + pub zero_pad: bool, + /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`. + pub debug_hex: Option<FormatDebugHex>, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatSign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatDebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, } #[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 0f8ebcfdc15..23c32fa96ca 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] -#![feature(slice_internals)] #![feature(stmt_expr_attributes)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_ast/src/util/unicode.rs b/compiler/rustc_ast/src/util/unicode.rs index 0eae791b25e..6f57d66b227 100644 --- a/compiler/rustc_ast/src/util/unicode.rs +++ b/compiler/rustc_ast/src/util/unicode.rs @@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool { // U+2069 - E2 81 A9 let mut bytes = s.as_bytes(); loop { - match core::slice::memchr::memchr(0xE2, bytes) { + match memchr::memchr(0xE2, bytes) { Some(idx) => { // bytes are valid UTF-8 -> E2 must be followed by two bytes let ch = &bytes[idx..idx + 3]; diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 776b532b0de..e7dd0b18a03 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -137,26 +137,43 @@ fn make_format_spec<'hir>( } Err(_) => ctx.expr(sp, hir::ExprKind::Err), }; - let fill = ctx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' ')); + let &FormatOptions { + ref width, + ref precision, + alignment, + fill, + sign, + alternate, + zero_pad, + debug_hex, + } = &placeholder.format_options; + let fill = ctx.expr_char(sp, fill.unwrap_or(' ')); let align = ctx.expr_lang_item_type_relative( sp, hir::LangItem::FormatAlignment, - match placeholder.format_options.alignment { + match alignment { Some(FormatAlignment::Left) => sym::Left, Some(FormatAlignment::Right) => sym::Right, Some(FormatAlignment::Center) => sym::Center, None => sym::Unknown, }, ); - let flags = ctx.expr_u32(sp, placeholder.format_options.flags); - let prec = make_count(ctx, sp, &placeholder.format_options.precision, argmap); - let width = make_count(ctx, sp, &placeholder.format_options.width, argmap); + // This needs to match `FlagV1` in library/core/src/fmt/mod.rs. + let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) + | ((sign == Some(FormatSign::Minus)) as u32) << 1 + | (alternate as u32) << 2 + | (zero_pad as u32) << 3 + | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4 + | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5; + let flags = ctx.expr_u32(sp, flags); + let precision = make_count(ctx, sp, &precision, argmap); + let width = make_count(ctx, sp, &width, argmap); let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative( sp, hir::LangItem::FormatPlaceholder, sym::new, )); - let args = ctx.arena.alloc_from_iter([position, fill, align, flags, prec, width]); + let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]); ctx.expr_call_mut(sp, format_placeholder_new, args) } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 63033085bec..f7fe0d771a1 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -275,19 +275,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'hir>, - fd: &'hir FnDecl<'hir>, - b: BodyId, - _: Span, - id: HirId, - ) { - assert_eq!(self.owner, id.owner); - assert_eq!(self.parent_node, id.local_id); - intravisit::walk_fn(self, fk, fd, b, id); - } - fn visit_block(&mut self, block: &'hir Block<'hir>) { self.insert(block.span, block.hir_id, Node::Block(block)); self.with_parent(block.hir_id, |this| { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5d2589cb2b2..2865082bd7a 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -67,7 +67,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { current_hir_id_owner: hir::CRATE_OWNER_ID, item_local_id_counter: hir::ItemLocalId::new(0), node_id_to_local_id: Default::default(), - local_id_to_def_id: SortedMap::new(), trait_map: Default::default(), // Lowering state. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 35849a6b944..a04a2595293 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -119,7 +119,6 @@ struct LoweringContext<'a, 'hir> { current_hir_id_owner: hir::OwnerId, item_local_id_counter: hir::ItemLocalId, - local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>, impl_trait_defs: Vec<hir::GenericParam<'hir>>, @@ -567,7 +566,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); - let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id }); @@ -594,7 +592,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; self.node_id_to_local_id = current_node_ids; - self.local_id_to_def_id = current_id_to_def_id; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; @@ -629,7 +626,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); - let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id); let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] @@ -645,13 +641,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies); let (nodes, parenting) = index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); - let nodes = hir::OwnerNodes { - hash_including_bodies, - hash_without_bodies, - nodes, - bodies, - local_id_to_def_id, - }; + let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; let attrs = { let hash = self.tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); @@ -710,7 +700,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { assert_ne!(local_id, hir::ItemLocalId::new(0)); if let Some(def_id) = self.opt_local_def_id(ast_node_id) { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.local_id_to_def_id.insert(local_id, def_id); } if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 99ffa19016f..cacfe9eb2f1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -6,7 +6,10 @@ use rustc_ast::token; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode}; -use rustc_ast::{FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatTrait}; +use rustc_ast::{ + FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, + FormatTrait, +}; use std::fmt::Write; impl<'a> State<'a> { @@ -675,17 +678,15 @@ pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> St Some(FormatAlignment::Center) => template.push_str("^"), None => {} } - let flags = p.format_options.flags; - if flags >> (rustc_parse_format::FlagSignPlus as usize) & 1 != 0 { - template.push('+'); - } - if flags >> (rustc_parse_format::FlagSignMinus as usize) & 1 != 0 { - template.push('-'); + match p.format_options.sign { + Some(FormatSign::Plus) => template.push('+'), + Some(FormatSign::Minus) => template.push('-'), + None => {} } - if flags >> (rustc_parse_format::FlagAlternate as usize) & 1 != 0 { + if p.format_options.alternate { template.push('#'); } - if flags >> (rustc_parse_format::FlagSignAwareZeroPad as usize) & 1 != 0 { + if p.format_options.zero_pad { template.push('0'); } if let Some(width) = &p.format_options.width { @@ -709,11 +710,10 @@ pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> St } } } - if flags >> (rustc_parse_format::FlagDebugLowerHex as usize) & 1 != 0 { - template.push('x'); - } - if flags >> (rustc_parse_format::FlagDebugUpperHex as usize) & 1 != 0 { - template.push('X'); + match p.format_options.debug_hex { + Some(FormatDebugHex::Lower) => template.push('x'), + Some(FormatDebugHex::Upper) => template.push('X'), + None => {} } template.push_str(match p.format_trait { FormatTrait::Display => "", diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index c9dc8921262..2fc30d8e05f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::MetaItem; +use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord( let attrs = thin_vec![cx.attr_word(sym::inline, span)]; + // Order in which to perform matching + let tag_then_data = if let Annotatable::Item(item) = item + && let ItemKind::Enum(def, _) = &item.kind { + let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); + match dataful.iter().filter(|&&b| b).count() { + // No data, placing the tag check first makes codegen simpler + 0 => true, + 1..=2 => false, + _ => { + (0..dataful.len()-1).any(|i| { + if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) { + idx >= 2 + } else { + false + } + }) + } + } + } else { + true + }; let partial_cmp_def = MethodDef { name: sym::partial_cmp, generics: Bounds::empty(), @@ -30,7 +51,7 @@ pub fn expand_deriving_partial_ord( attributes: attrs, fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) + cs_partial_cmp(cx, span, substr, tag_then_data) })), }; @@ -47,7 +68,12 @@ pub fn expand_deriving_partial_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +fn cs_partial_cmp( + cx: &mut ExtCtxt<'_>, + span: Span, + substr: &Substructure<'_>, + tag_then_data: bool, +) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); @@ -74,12 +100,50 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ let args = vec![field.self_expr.clone(), other_expr.clone()]; cx.expr_call_global(field.span, partial_cmp_path.clone(), args) } - CsFold::Combine(span, expr1, expr2) => { - let eq_arm = - cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); - let neq_arm = - cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + CsFold::Combine(span, mut expr1, expr2) => { + // When the item is an enum, this expands to + // ``` + // match (expr2) { + // Some(Ordering::Equal) => expr1, + // cmp => cmp + // } + // ``` + // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum tags, + // before either inspecting their contents (if they match), or returning + // the `cmp::Ordering` of comparing the enum tags. + // ``` + // match partial_cmp(self_tag, other_tag) { + // Some(Ordering::Equal) => match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), + // _ => Some(Ordering::Equal) + // } + // cmp => cmp + // } + // ``` + // If we have any certain enum layouts, flipping this results in better codegen + // ``` + // match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // _ => partial_cmp(self_tag, other_tag) + // } + // ``` + // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 + + if !tag_then_data + && let ExprKind::Match(_, arms) = &mut expr1.kind + && let Some(last) = arms.last_mut() + && let PatKind::Wild = last.pat.kind { + last.body = expr2; + expr1 + } else { + let eq_arm = + cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); + let neq_arm = + cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); + cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + } } CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), }, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 469f0dc1303..e93a23394c0 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -4,7 +4,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, - FormatOptions, FormatPlaceholder, FormatTrait, + FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; @@ -435,7 +435,16 @@ pub fn make_format_args( format_options: FormatOptions { fill: format.fill, alignment, - flags: format.flags, + sign: format.sign.map(|s| match s { + parse::Sign::Plus => FormatSign::Plus, + parse::Sign::Minus => FormatSign::Minus, + }), + alternate: format.alternate, + zero_pad: format.zero_pad, + debug_hex: format.debug_hex.map(|s| match s { + parse::DebugHex::Lower => FormatDebugHex::Lower, + parse::DebugHex::Upper => FormatDebugHex::Upper, + }), precision, width, }, diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 426f57c0608..58ca87524de 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -15,8 +15,8 @@ use crate::errors::{ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, - ArchiveBuilderBuilder, UnknownArchiveKind, + get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder, + ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind, }; use rustc_session::cstore::DllImport; @@ -66,7 +66,13 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { archive: &Path, skip: Box<dyn FnMut(&str) -> bool + 'static>, ) -> io::Result<()> { - let archive_ro = match ArchiveRO::open(archive) { + let mut archive = archive.to_path_buf(); + if self.sess.target.llvm_target.contains("-apple-macosx") { + if let Some(new_archive) = try_extract_macho_fat_archive(&self.sess, &archive)? { + archive = new_archive + } + } + let archive_ro = match ArchiveRO::open(&archive) { Ok(ar) => ar, Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), }; @@ -74,7 +80,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { return Ok(()); } self.additions.push(Addition::Archive { - path: archive.to_path_buf(), + path: archive, archive: archive_ro, skip: Box::new(skip), }); @@ -102,7 +108,9 @@ pub struct LlvmArchiveBuilderBuilder; impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> { - if sess.target.arch == "wasm32" || sess.target.arch == "wasm64" { + // FIXME use ArArchiveBuilder on most targets again once reading thin archives is + // implemented + if true || sess.target.arch == "wasm32" || sess.target.arch == "wasm64" { Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) } else { Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols)) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d9ccba07a34..32cd3a4efa2 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -191,7 +191,7 @@ pub unsafe fn create_module<'ll>( // // FIXME(#34960) let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = cfg_llvm_root.trim() != ""; + let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); if !custom_llvm_used && target_data_layout != llvm_data_layout { bug!( diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index d9a73c7a5c9..240a9d2f371 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -295,9 +295,8 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator ) { return None; - } else if ignore_unused_generics - && tcx.generics_of(def_id).requires_monomorphization(tcx) - { + } + if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) { return None; } Some(local_def_id.to_def_id()) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index b6eb5ee183f..f73bbf3d22b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1499,6 +1499,11 @@ pub fn create_vtable_di_node<'ll, 'tcx>( return; } + // When full debuginfo is enabled, we want to try and prevent vtables from being + // merged. Otherwise debuggers will have a hard time mapping from dyn pointer + // to concrete type. + llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 6eb120157da..d3cd085cfb6 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -14,7 +14,7 @@ use tempfile::Builder as TempFileBuilder; use std::error::Error; use std::fs::File; -use std::io; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; // Re-exporting for rustc_codegen_llvm::back::archive @@ -116,11 +116,12 @@ impl<'a> ArArchiveBuilder<'a> { } } -fn try_filter_fat_archs<'a>( +fn try_filter_fat_archs( archs: object::read::Result<&[impl FatArch]>, target_arch: object::Architecture, - archive_map_data: &'a [u8], -) -> io::Result<Option<(&'a [u8], u64)>> { + archive_path: &Path, + archive_map_data: &[u8], +) -> io::Result<Option<PathBuf>> { let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let desired = match archs.iter().find(|a| a.architecture() == target_arch) { @@ -128,30 +129,38 @@ fn try_filter_fat_archs<'a>( None => return Ok(None), }; - Ok(Some(( + let (mut new_f, extracted_path) = tempfile::Builder::new() + .suffix(archive_path.file_name().unwrap()) + .tempfile()? + .keep() + .unwrap(); + + new_f.write_all( desired.data(archive_map_data).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?, - desired.offset().into(), - ))) + )?; + + Ok(Some(extracted_path)) } -pub fn try_extract_macho_fat_archive<'a>( +pub fn try_extract_macho_fat_archive( sess: &Session, - archive_bytes: &'a [u8], -) -> io::Result<Option<(&'a [u8], u64)>> { + archive_path: &Path, +) -> io::Result<Option<PathBuf>> { + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; let target_arch = match sess.target.arch.as_ref() { "aarch64" => object::Architecture::Aarch64, "x86_64" => object::Architecture::X86_64, _ => return Ok(None), }; - match object::macho::FatHeader::parse(archive_bytes) { + match object::macho::FatHeader::parse(&*archive_map) { Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC => { - let archs = object::macho::FatHeader::parse_arch32(archive_bytes); - try_filter_fat_archs(archs, target_arch, archive_bytes) + let archs = object::macho::FatHeader::parse_arch32(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) } Ok(h) if h.magic.get(object::endian::BigEndian) == object::macho::FAT_MAGIC_64 => { - let archs = object::macho::FatHeader::parse_arch64(archive_bytes); - try_filter_fat_archs(archs, target_arch, archive_bytes) + let archs = object::macho::FatHeader::parse_arch64(&*archive_map); + try_filter_fat_archs(archs, target_arch, archive_path, &*archive_map) } // Not a FatHeader at all, just return None. _ => Ok(None), @@ -164,24 +173,21 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { archive_path: &Path, mut skip: Box<dyn FnMut(&str) -> bool + 'static>, ) -> io::Result<()> { - let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let mut archive_path = archive_path.to_path_buf(); + if self.sess.target.llvm_target.contains("-apple-macosx") { + if let Some(new_archive_path) = + try_extract_macho_fat_archive(&self.sess, &archive_path)? + { + archive_path = new_archive_path + } + } + if self.src_archives.iter().any(|archive| archive.0 == archive_path) { return Ok(()); } - let (archive_bytes, offset) = if self.sess.target.llvm_target.contains("-apple-macosx") { - if let Some((sub_archive, archive_offset)) = - try_extract_macho_fat_archive(&self.sess, &*archive_map)? - { - (sub_archive, Some(archive_offset)) - } else { - (&*archive_map, None) - } - } else { - (&*archive_map, None) - }; - - let archive = ArchiveFile::parse(&*archive_bytes) + let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? }; + let archive = ArchiveFile::parse(&*archive_map) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; let archive_index = self.src_archives.len(); @@ -190,13 +196,9 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { let file_name = String::from_utf8(entry.name().to_vec()) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; if !skip(&file_name) { - let mut range = entry.file_range(); - if let Some(offset) = offset { - range.0 += offset; - } self.entries.push(( file_name.into_bytes(), - ArchiveEntry::FromArchive { archive_index, file_range: range }, + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, )); } } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1599ccbb259..b0e007ce009 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -414,6 +414,7 @@ fn push_debuginfo_type_name<'tcx>( | ty::Placeholder(..) | ty::Alias(..) | ty::Bound(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => { bug!( "debuginfo: Trying to create type name for \ diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index dd1ac2c74ae..95aad10fdb0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -36,7 +36,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Arguments get assigned to by means of the function being called for arg in mir.args_iter() { - analyzer.assign(arg, mir::START_BLOCK.start_location()); + analyzer.assign(arg, DefLocation::Argument); } // If there exists a local definition that dominates all uses of that local, @@ -64,7 +64,22 @@ enum LocalKind { /// A scalar or a scalar pair local that is neither defined nor used. Unused, /// A scalar or a scalar pair local with a single definition that dominates all uses. - SSA(mir::Location), + SSA(DefLocation), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +enum DefLocation { + Argument, + Body(Location), +} + +impl DefLocation { + fn dominates(self, location: Location, dominators: &Dominators<mir::BasicBlock>) -> bool { + match self { + DefLocation::Argument => true, + DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators), + } + } } struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { @@ -74,17 +89,13 @@ struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { } impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { - fn assign(&mut self, local: mir::Local, location: Location) { + fn assign(&mut self, local: mir::Local, location: DefLocation) { let kind = &mut self.locals[local]; match *kind { LocalKind::ZST => {} LocalKind::Memory => {} - LocalKind::Unused => { - *kind = LocalKind::SSA(location); - } - LocalKind::SSA(_) => { - *kind = LocalKind::Memory; - } + LocalKind::Unused => *kind = LocalKind::SSA(location), + LocalKind::SSA(_) => *kind = LocalKind::Memory, } } @@ -166,7 +177,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> debug!("visit_assign(place={:?}, rvalue={:?})", place, rvalue); if let Some(local) = place.as_local() { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); if self.locals[local] != LocalKind::Memory { let decl_span = self.fx.mir.local_decls[local].source_info.span; if !self.fx.rvalue_creates_operand(rvalue, decl_span) { @@ -189,7 +200,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> match context { PlaceContext::MutatingUse(MutatingUseContext::Call) | PlaceContext::MutatingUse(MutatingUseContext::Yield) => { - self.assign(local, location); + self.assign(local, DefLocation::Body(location)); } PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 498c0087387..c52886b77e6 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -151,7 +151,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>( // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) | ty::Generator(..) - | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType), + | ty::GeneratorWitness(..) |ty::GeneratorWitnessMIR(..)=> Err(ValTreeCreationError::NonSupportedType), } } @@ -314,6 +314,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::FnPtr(_) | ty::RawPtr(_) | ty::Str diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f87e4fbc1a1..907f014dfb5 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -101,6 +101,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) | ty::Never | ty::Tuple(_) | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx), diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 19e359986a1..aa539516d5e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -602,6 +602,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Bound(..) | ty::Param(..) | ty::Alias(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 3f83d40755a..fab92f6f6f3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -372,12 +372,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { return; }; - let Some(&f_ty) = layout.field_tys.get(local) else { + let Some(f_ty) = layout.field_tys.get(local) else { self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty)); return; }; - f_ty + f_ty.ty } else { let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { fail_out_of_bounds(self, location); diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index c4122f66498..4e80a285186 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -64,6 +64,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { ty::Foreign(def_id) => self.print_def_path(def_id, &[]), ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), + ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"), } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0587.md b/compiler/rustc_error_codes/src/error_codes/E0587.md index ee9031dc379..d7998af85b9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0587.md +++ b/compiler/rustc_error_codes/src/error_codes/E0587.md @@ -11,6 +11,6 @@ You cannot use `packed` and `align` hints on a same type. If you want to pack a type to a given size, you should provide a size to packed: ``` -#[repr(packed)] // ok! +#[repr(packed(8))] // ok! struct Umbrella(i32); ``` diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl index 08ce5172574..6101b28ab0c 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl @@ -23,7 +23,7 @@ codegen_gcc_invalid_monomorphization_unsupported_element = invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}` codegen_gcc_invalid_monomorphization_invalid_bitmask = - invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` + invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` codegen_gcc_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}` diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl index c8c7afb5f91..4924105128d 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl @@ -179,9 +179,9 @@ codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$ codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` -codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error} +codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} -codegen_ssa_read_file = failed to read file: {message} +codegen_ssa_read_file = failed to read file: {$message} codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 51b2ff6a003..4ad24c1400d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -629,19 +629,27 @@ impl Diagnostic { applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { - assert!(!suggestion.is_empty()); - debug_assert!( - !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())), - "Span must not be empty and have no suggestion" + let mut parts = suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect::<Vec<_>>(); + + parts.sort_unstable_by_key(|part| part.span); + + assert!(!parts.is_empty()); + debug_assert_eq!( + parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), + None, + "Span must not be empty and have no suggestion", + ); + debug_assert_eq!( + parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), + None, + "suggestion must not have overlapping parts", ); self.push_suggestion(CodeSuggestion { - substitutions: vec![Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], + substitutions: vec![Substitution { parts }], msg: self.subdiagnostic_message_to_diagnostic_message(msg), style, applicability, @@ -802,25 +810,34 @@ impl Diagnostic { suggestions: impl IntoIterator<Item = Vec<(Span, String)>>, applicability: Applicability, ) -> &mut Self { - let suggestions: Vec<_> = suggestions.into_iter().collect(); - debug_assert!( - !(suggestions - .iter() - .flatten() - .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())), - "Span must not be empty and have no suggestion" - ); + let substitutions = suggestions + .into_iter() + .map(|sugg| { + let mut parts = sugg + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect::<Vec<_>>(); + + parts.sort_unstable_by_key(|part| part.span); + + assert!(!parts.is_empty()); + debug_assert_eq!( + parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()), + None, + "Span must not be empty and have no suggestion", + ); + debug_assert_eq!( + parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), + None, + "suggestion must not have overlapping parts", + ); + + Substitution { parts } + }) + .collect(); self.push_suggestion(CodeSuggestion { - substitutions: suggestions - .into_iter() - .map(|sugg| Substitution { - parts: sugg - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }) - .collect(), + substitutions, msg: self.subdiagnostic_message_to_diagnostic_message(msg), style: SuggestionStyle::ShowCode, applicability, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 535812fb0e2..d076fc08b0e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,6 +3,7 @@ //! This module contains the code for creating and emitting diagnostics. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(drain_filter)] #![feature(if_let_guard)] #![feature(is_terminal)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 4ebd75f0185..cd431f57019 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -10,7 +10,7 @@ use crate::mbe::transcribe::transcribe; use rustc_ast as ast; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; @@ -212,7 +212,6 @@ fn expand_macro<'cx>( }; let arm_span = rhses[i].span(); - let rhs_spans = rhs.tts.iter().map(|t| t.span()).collect::<Vec<_>>(); // rhs has holes ( `$id` and `$(...)` that need filled) let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) { Ok(tts) => tts, @@ -224,12 +223,25 @@ fn expand_macro<'cx>( // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. - if rhs_spans.len() == tts.len() { + if tts.len() == rhs.tts.len() { tts = tts.map_enumerated(|i, tt| { let mut tt = tt.clone(); - let mut sp = rhs_spans[i]; - sp = sp.with_ctxt(tt.span().ctxt()); - tt.set_span(sp); + let rhs_tt = &rhs.tts[i]; + let ctxt = tt.span().ctxt(); + match (&mut tt, rhs_tt) { + // preserve the delim spans if able + ( + TokenTree::Delimited(target_sp, ..), + mbe::TokenTree::Delimited(source_sp, ..), + ) => { + target_sp.open = source_sp.open.with_ctxt(ctxt); + target_sp.close = source_sp.close.with_ctxt(ctxt); + } + _ => { + let sp = rhs_tt.span().with_ctxt(ctxt); + tt.set_span(sp); + } + } tt }); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5a620263e42..4696a4bd9ab 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -831,8 +831,6 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, - /// Non-owning definitions contained in this owner. - pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>, } impl<'tcx> OwnerNodes<'tcx> { @@ -862,7 +860,6 @@ impl fmt::Debug for OwnerNodes<'_> { .collect::<Vec<_>>(), ) .field("bodies", &self.bodies) - .field("local_id_to_def_id", &self.local_id_to_def_id) .field("hash_without_bodies", &self.hash_without_bodies) .field("hash_including_bodies", &self.hash_including_bodies) .finish() @@ -2106,8 +2103,8 @@ pub enum LocalSource { } /// Hints at the original code for a `match _ { .. }`. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)] -#[derive(HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum MatchSource { /// A `match _ { .. }`. Normal, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 02641b7cf8f..f632babab0b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -67,6 +67,7 @@ use crate::hir::*; use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -364,7 +365,7 @@ pub trait Visitor<'v>: Sized { fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) { walk_fn_decl(self, fd) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: LocalDefId) { walk_fn(self, fk, fd, b, id) } fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) { @@ -468,13 +469,16 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { visitor.visit_ty(typ); visitor.visit_nested_body(body); } - ItemKind::Fn(ref sig, ref generics, body_id) => visitor.visit_fn( - FnKind::ItemFn(item.ident, generics, sig.header), - sig.decl, - body_id, - item.span, - item.hir_id(), - ), + ItemKind::Fn(ref sig, ref generics, body_id) => { + visitor.visit_id(item.hir_id()); + visitor.visit_fn( + FnKind::ItemFn(item.ident, generics, sig.header), + sig.decl, + body_id, + item.span, + item.owner_id.def_id, + ) + } ItemKind::Macro(..) => { visitor.visit_id(item.hir_id()); } @@ -733,7 +737,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(&Closure { - def_id: _, + def_id, binder: _, bound_generic_params, fn_decl, @@ -745,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); - visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) + visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id) } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); @@ -923,9 +927,8 @@ pub fn walk_fn<'v, V: Visitor<'v>>( function_kind: FnKind<'v>, function_declaration: &'v FnDecl<'v>, body_id: BodyId, - id: HirId, + _: LocalDefId, ) { - visitor.visit_id(id); visitor.visit_fn_decl(function_declaration); walk_fn_kind(visitor, function_kind); visitor.visit_nested_body(body_id) @@ -953,26 +956,30 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); visitor.visit_ident(ident); - visitor.visit_generics(generics); - visitor.visit_defaultness(defaultness); + visitor.visit_generics(&generics); + visitor.visit_defaultness(&defaultness); + visitor.visit_id(hir_id); match *kind { TraitItemKind::Const(ref ty, default) => { - visitor.visit_id(hir_id); visitor.visit_ty(ty); walk_list!(visitor, visit_nested_body, default); } TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { - visitor.visit_id(hir_id); visitor.visit_fn_decl(sig.decl); for ¶m_name in param_names { visitor.visit_ident(param_name); } } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { - visitor.visit_fn(FnKind::Method(ident, sig), sig.decl, body_id, span, hir_id); + visitor.visit_fn( + FnKind::Method(ident, sig), + sig.decl, + body_id, + span, + trait_item.owner_id.def_id, + ); } TraitItemKind::Type(bounds, ref default) => { - visitor.visit_id(hir_id); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, default); } @@ -1002,9 +1009,9 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_ident(ident); visitor.visit_generics(generics); visitor.visit_defaultness(defaultness); + visitor.visit_id(impl_item.hir_id()); match *kind { ImplItemKind::Const(ref ty, body) => { - visitor.visit_id(impl_item.hir_id()); visitor.visit_ty(ty); visitor.visit_nested_body(body); } @@ -1014,11 +1021,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt sig.decl, body_id, impl_item.span, - impl_item.hir_id(), + impl_item.owner_id.def_id, ); } ImplItemKind::Type(ref ty) => { - visitor.visit_id(impl_item.hir_id()); visitor.visit_ty(ty); } } diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 23423e8f3b3..85d0e02d0b6 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -100,13 +100,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // the body satisfies the condition of two nodes being different have different // `hash_stable` results. - let OwnerNodes { - hash_including_bodies, - hash_without_bodies: _, - nodes: _, - bodies: _, - local_id_to_def_id: _, - } = *self; + let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = + *self; hash_including_bodies.hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 27284f8b983..caf26a75d3c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -27,7 +27,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; @@ -37,7 +37,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::astconv_object_safety_violations; @@ -54,7 +54,7 @@ use std::slice; pub struct PathSeg(pub DefId, pub usize); pub trait AstConv<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + fn tcx(&self) -> TyCtxt<'tcx>; fn item_def_id(&self) -> DefId; @@ -131,6 +131,8 @@ pub trait AstConv<'tcx> { { self } + + fn infcx(&self) -> Option<&InferCtxt<'tcx>>; } #[derive(Debug)] @@ -2132,48 +2134,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .emit() // Already reported in an earlier stage. } else { - // Find all the `impl`s that `qself_ty` has for any trait that has the - // associated type, so that we suggest the right one. - let infcx = tcx.infer_ctxt().build(); - // We create a fresh `ty::ParamEnv` instead of the one for `self.item_def_id()` - // to avoid a cycle error in `src/test/ui/resolve/issue-102946.rs`. - let param_env = ty::ParamEnv::empty(); - let traits: Vec<_> = self - .tcx() - .all_traits() - .filter(|trait_def_id| { - // Consider only traits with the associated type - tcx.associated_items(*trait_def_id) - .in_definition_order() - .any(|i| { - i.kind.namespace() == Namespace::TypeNS - && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident - && matches!(i.kind, ty::AssocKind::Type) - }) - // Consider only accessible traits - && tcx.visibility(*trait_def_id) - .is_accessible_from(self.item_def_id(), tcx) - && tcx.all_impls(*trait_def_id) - .any(|impl_def_id| { - let trait_ref = tcx.impl_trait_ref(impl_def_id); - trait_ref.map_or(false, |trait_ref| { - let impl_ = trait_ref.subst( - tcx, - infcx.fresh_substs_for_item(span, impl_def_id), - ); - infcx - .can_eq( - param_env, - tcx.erase_regions(impl_.self_ty()), - tcx.erase_regions(qself_ty), - ) - .is_ok() - }) - && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative - }) - }) - .map(|trait_def_id| tcx.def_path_str(trait_def_id)) - .collect(); + let traits: Vec<_> = + self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); // Don't print `TyErr` to the user. self.report_ambiguous_associated_type( @@ -2232,6 +2194,60 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ok((ty, DefKind::AssocTy, assoc_ty_did)) } + fn probe_traits_that_match_assoc_ty( + &self, + qself_ty: Ty<'tcx>, + assoc_ident: Ident, + ) -> Vec<String> { + let tcx = self.tcx(); + + // In contexts that have no inference context, just make a new one. + // We do need a local variable to store it, though. + let infcx_; + let infcx = if let Some(infcx) = self.infcx() { + infcx + } else { + assert!(!qself_ty.needs_infer()); + infcx_ = tcx.infer_ctxt().build(); + &infcx_ + }; + + tcx.all_traits() + .filter(|trait_def_id| { + // Consider only traits with the associated type + tcx.associated_items(*trait_def_id) + .in_definition_order() + .any(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident + && matches!(i.kind, ty::AssocKind::Type) + }) + // Consider only accessible traits + && tcx.visibility(*trait_def_id) + .is_accessible_from(self.item_def_id(), tcx) + && tcx.all_impls(*trait_def_id) + .any(|impl_def_id| { + let trait_ref = tcx.impl_trait_ref(impl_def_id); + trait_ref.map_or(false, |trait_ref| { + let impl_ = trait_ref.subst( + tcx, + infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id), + ); + infcx + .can_eq( + ty::ParamEnv::empty(), + tcx.erase_regions(impl_.self_ty()), + tcx.erase_regions(qself_ty), + ) + .is_ok() + }) + && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative + }) + }) + .map(|trait_def_id| tcx.def_path_str(trait_def_id)) + .collect() + } + fn lookup_assoc_ty( &self, ident: Ident, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 6c7482b40c3..6f4ebc987e6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -14,7 +14,7 @@ use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; @@ -28,7 +28,7 @@ use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCtxt}; +use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _}; use std::ops::ControlFlow; @@ -665,7 +665,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { DefKind::GlobalAsm => { let it = tcx.hir().item(id); let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; - InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id()); + InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); } _ => {} } @@ -1460,7 +1460,8 @@ fn opaque_type_cycle_error( for def_id in visitor.opaques { let ty_span = tcx.def_span(def_id); if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{ty}`")); + let descr = if ty.is_impl_trait() { "opaque " } else { "" }; + err.span_label(ty_span, &format!("returning this {descr}type `{ty}`")); seen.insert(ty_span); } err.span_label(sp, &format!("returning here with type `{ty}`")); @@ -1507,3 +1508,34 @@ fn opaque_type_cycle_error( } err.emit() } + +pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) { + debug_assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); + debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Generator)); + + let typeck = tcx.typeck(def_id); + let param_env = tcx.param_env(def_id); + + let generator_interior_predicates = &typeck.generator_interior_predicates[&def_id]; + debug!(?generator_interior_predicates); + + let infcx = tcx + .infer_ctxt() + // typeck writeback gives us predicates with their regions erased. + // As borrowck already has checked lifetimes, we do not need to do it again. + .ignoring_regions() + // Bind opaque types to `def_id` as they should have been checked by borrowck. + .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) + .build(); + + let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); + for (predicate, cause) in generator_interior_predicates { + let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate); + fulfillment_cx.register_predicate_obligation(&infcx, obligation); + } + let errors = fulfillment_cx.select_all_or_error(&infcx); + debug!(?errors); + if !errors.is_empty() { + infcx.err_ctxt().report_fulfillment_errors(&errors, None); + } +} diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 82030d82f57..122b6ead8e9 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy}; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::{Symbol, DUMMY_SP}; use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; @@ -253,10 +254,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Some(asm_ty) } - pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) { - let hir = self.tcx.hir(); - let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id(); - let target_features = self.tcx.asm_target_features(enclosing_def_id); + pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { + let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); let Some(asm_arch) = self.tcx.sess.asm_arch else { self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm"); return; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 2f2ee702837..bec693439a4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -105,6 +105,7 @@ pub fn provide(providers: &mut Providers) { region_scope_tree, collect_return_position_impl_trait_in_trait_tys, compare_impl_const: compare_impl_item::compare_impl_const_raw, + check_generator_obligations: check::check_generator_obligations, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 870c57d5e05..e15b7c89730 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -391,7 +391,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe gather_gat_bounds( tcx, param_env, - item_def_id.def_id, + item_def_id, sig.inputs_and_output, // We also assume that all of the function signature's parameter types // are well formed. @@ -413,7 +413,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe gather_gat_bounds( tcx, param_env, - item_def_id.def_id, + item_def_id, tcx.explicit_item_bounds(item_def_id).to_vec(), &FxIndexSet::default(), gat_def_id.def_id, @@ -563,7 +563,7 @@ fn augment_param_env<'tcx>( fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - item_def_id: LocalDefId, + item_def_id: hir::OwnerId, to_check: T, wf_tys: &FxIndexSet<Ty<'tcx>>, gat_def_id: LocalDefId, @@ -596,7 +596,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( // reflected in a where clause on the GAT itself. for (ty, ty_idx) in &types { // In our example, requires that `Self: 'a` - if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) { + if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { debug!(?ty_idx, ?region_a_idx); debug!("required clause: {ty} must outlive {region_a}"); // Translate into the generic parameters of the GAT. In @@ -634,7 +634,14 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( if ty::ReStatic == **region_b || region_a == region_b { continue; } - if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) { + if region_known_to_outlive( + tcx, + item_def_id.def_id, + param_env, + &wf_tys, + *region_a, + *region_b, + ) { debug!(?region_a_idx, ?region_b_idx); debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index dfb98240943..c1b0237b2d1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -240,6 +240,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b73a05ff398..f5a1e51c07b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -25,7 +25,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; @@ -517,6 +517,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) { // There's no place to record types from signatures? } + + fn infcx(&self) -> Option<&InferCtxt<'tcx>> { + None + } } /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs index 359122d4e16..3c67722b637 100644 --- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs +++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs @@ -829,7 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fd: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, _: Span, - _: hir::HirId, + _: LocalDefId, ) { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, @@ -1264,14 +1264,21 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } else if let Some(body_id) = outermost_body { let fn_id = self.tcx.hir().body_owner(body_id); match self.tcx.hir().get(fn_id) { - Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) + Node::Item(hir::Item { owner_id, kind: hir::ItemKind::Fn(..), .. }) | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(..), .. + owner_id, + kind: hir::TraitItemKind::Fn(..), + .. }) - | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) - | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { - let scope = self.tcx.hir().local_def_id(fn_id); - def = Region::Free(scope.to_def_id(), def.id().unwrap()); + | Node::ImplItem(hir::ImplItem { + owner_id, + kind: hir::ImplItemKind::Fn(..), + .. + }) => { + def = Region::Free(owner_id.to_def_id(), def.id().unwrap()); + } + Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => { + def = Region::Free(closure.def_id.to_def_id(), def.id().unwrap()); } _ => {} } @@ -1658,10 +1665,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// "Constrained" basically means that it appears in any type but /// not amongst the inputs to a projection. In other words, `<&'a /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`. -fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?; - let generics = tcx.hir().get_generics(def_id)?; +fn is_late_bound_map( + tcx: TyCtxt<'_>, + owner_id: hir::OwnerId, +) -> Option<&FxIndexSet<hir::ItemLocalId>> { + let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?; + let generics = tcx.hir().get_generics(owner_id.def_id)?; let mut late_bound = FxIndexSet::default(); @@ -1695,24 +1704,22 @@ fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet< hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue, } - let param_def_id = tcx.hir().local_def_id(param.hir_id); - // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(¶m_def_id) { + if appears_in_where_clause.regions.contains(¶m.def_id) { continue; } // does not appear in the inputs, but appears in the return type? early-bound. - if !constrained_by_input.regions.contains(¶m_def_id) - && appears_in_output.regions.contains(¶m_def_id) + if !constrained_by_input.regions.contains(¶m.def_id) + && appears_in_output.regions.contains(¶m.def_id) { continue; } - debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id); + debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.def_id); - let inserted = late_bound.insert(param_def_id); - assert!(inserted, "visited lifetime {:?} twice", param.hir_id); + let inserted = late_bound.insert(param.hir_id.local_id); + assert!(inserted, "visited lifetime {:?} twice", param.def_id); } debug!(?late_bound); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 46b277d9803..d0d67ae9257 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -280,7 +280,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue }; - let dup_def = tcx.hir().local_def_id(duplicate.hir_id).to_def_id(); + let dup_def = duplicate.def_id.to_def_id(); let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() }; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index d0d819d9687..e7b0846e103 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -54,15 +54,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // ty which is a fully resolved projection. // For the code example above, this would mean converting Self::Assoc<3> // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>) - let item_hir_id = tcx + let item_def_id = tcx .hir() - .parent_iter(hir_id) - .filter(|(_, node)| matches!(node, Node::Item(_))) - .map(|(id, _)| id) - .next() - .unwrap(); - let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id(); - let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>; + .parent_owner_iter(hir_id) + .find(|(_, node)| matches!(node, OwnerNode::Item(_))) + .unwrap() + .0 + .to_def_id(); + let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>; let ty = item_ctxt.ast_ty_to_ty(hir_ty); // Iterate through the generics of the projection to find the one that corresponds to diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 2cd2b6a5f76..165782f209a 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -225,8 +225,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Ref(region, ty, mutbl) => { - let contra = self.contravariant(variance); - self.add_constraints_from_region(current, region, contra); + self.add_constraints_from_region(current, region, variance); self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); } @@ -258,9 +257,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Dynamic(data, r, _) => { - // The type `Foo<T+'a>` is contravariant w/r/t `'a`: - let contra = self.contravariant(variance); - self.add_constraints_from_region(current, r, contra); + // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`: + self.add_constraints_from_region(current, r, variance); if let Some(poly_trait_ref) = data.principal() { self.add_constraints_from_invariant_substs( @@ -295,12 +293,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Bound(..) | ty::Infer(..) => { - bug!( - "unexpected type encountered in \ - variance inference: {}", - ty - ); + ty::Placeholder(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Bound(..) + | ty::Infer(..) => { + bug!("unexpected type encountered in variance inference: {}", ty); } } } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 73aba2780d6..88fb2653586 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -186,6 +186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>, ) { let hir = self.tcx.hir(); + // First, check that we're actually in the tail of a function. let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; }; let body = hir.body(body_id); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 712f9b87aed..8e21c084841 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::FnDef(..) diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 8bbbf04c0cd..1c70c1b71e7 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -130,7 +130,12 @@ pub(super) fn check_fn<'a, 'tcx>( let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { let interior = fcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + fcx.deferred_generator_interiors.borrow_mut().push(( + fn_def_id, + body.id(), + interior, + gen_kind, + )); let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); Some(GeneratorTypes { @@ -167,12 +172,12 @@ pub(super) fn check_fn<'a, 'tcx>( // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` if let Some(panic_impl_did) = tcx.lang_items().panic_impl() - && panic_impl_did == hir.local_def_id(fn_id).to_def_id() + && panic_impl_did == fn_def_id.to_def_id() { check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty); } - if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == hir.local_def_id(fn_id).to_def_id() { + if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { check_lang_start_fn(tcx, fn_sig, decl, fn_def_id); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index e9858aef6d0..a355a54d695 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -517,16 +517,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { + if self.tcx.sess.opts.unstable_opts.drop_tracking_mir { + self.save_generator_interior_predicates(def_id); + return; + } + + self.select_obligations_where_possible(|_| {}); + let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior, kind) in generators.drain(..) { - self.select_obligations_where_possible(|_| {}); + for (_, body_id, interior, kind) in generators.drain(..) { crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + self.select_obligations_where_possible(|_| {}); + } + } + + /// Unify the inference variables corresponding to generator witnesses, and save all the + /// predicates that were stalled on those inference variables. + /// + /// This process allows to conservatively save all predicates that do depend on the generator + /// interior types, for later processing by `check_generator_obligations`. + /// + /// We must not attempt to select obligations after this method has run, or risk query cycle + /// ICE. + #[instrument(level = "debug", skip(self))] + fn save_generator_interior_predicates(&self, def_id: DefId) { + // Try selecting all obligations that are not blocked on inference variables. + // Once we start unifying generator witnesses, trying to select obligations on them will + // trigger query cycle ICEs, as doing so requires MIR. + self.select_obligations_where_possible(|_| {}); + + let generators = std::mem::take(&mut *self.deferred_generator_interiors.borrow_mut()); + debug!(?generators); + + for &(expr_def_id, body_id, interior, _) in generators.iter() { + debug!(?expr_def_id); + + // Create the `GeneratorWitness` type that we will unify with `interior`. + let substs = ty::InternalSubsts::identity_for_item( + self.tcx, + self.tcx.typeck_root_def_id(expr_def_id.to_def_id()), + ); + let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs); + + // Unify `interior` with `witness` and collect all the resulting obligations. + let span = self.tcx.hir().body(body_id).value.span; + let ok = self + .at(&self.misc(span), self.param_env) + .eq(interior, witness) + .expect("Failed to unify generator interior type"); + let mut obligations = ok.obligations; + + // Also collect the obligations that were unstalled by this unification. + obligations + .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx)); + + let obligations = obligations.into_iter().map(|o| (o.predicate, o.cause)).collect(); + debug!(?obligations); + self.typeck_results + .borrow_mut() + .generator_interior_predicates + .insert(expr_def_id, obligations); } } #[instrument(skip(self), level = "debug")] - pub(in super::super) fn select_all_obligations_or_error(&self) { - let mut errors = self.fulfillment_cx.borrow_mut().select_all_or_error(&self); + pub(in super::super) fn report_ambiguity_errors(&self) { + let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(); if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e78c76d5dde..47ef106e750 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) - .check_asm(asm, self.tcx.hir().local_def_id_to_hir_id(enclosing_id)); + .check_asm(asm, enclosing_id); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 8724e69cc51..4940015ddd5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -324,6 +324,10 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; self.write_ty(hir_id, ty) } + + fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { + Some(&self.infcx) + } } /// Represents a user-provided type in the raw form (never normalized). diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 15dd3412c34..38445f28440 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -5,6 +5,7 @@ use rustc_hir::PatKind; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::Ty; use rustc_middle::ty::UserType; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; @@ -156,7 +157,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { _: &'tcx hir::FnDecl<'tcx>, _: hir::BodyId, _: Span, - _: hir::HirId, + _: LocalDefId, ) { } } diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index ba34f299453..87e54025330 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -56,7 +56,7 @@ pub struct Inherited<'tcx> { pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>, pub(super) deferred_generator_interiors: - RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, + RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, pub(super) body_id: Option<hir::BodyId>, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 04ac9c085ea..323bacf70ab 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -294,14 +294,24 @@ fn typeck_with_fallback<'tcx>( // Before the generator analysis, temporary scopes shall be marked to provide more // precise information on types to be captured. fcx.resolve_rvalue_scopes(def_id.to_def_id()); - fcx.resolve_generator_interiors(def_id.to_def_id()); for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { let ty = fcx.normalize(span, ty); fcx.require_type_is_sized(ty, span, code); } - fcx.select_all_obligations_or_error(); + fcx.select_obligations_where_possible(|_| {}); + + debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); + + // This must be the last thing before `report_ambiguity_errors`. + fcx.resolve_generator_interiors(def_id.to_def_id()); + + debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); + + if let None = fcx.infcx.tainted_by_errors() { + fcx.report_ambiguity_errors(); + } if let None = fcx.infcx.tainted_by_errors() { fcx.check_transmutes(); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 250f4cd3f65..0aa34f9dd70 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -40,8 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, body: &'tcx hir::Body<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { - let item_id = self.tcx.hir().body_owner(body.id()); - let item_def_id = self.tcx.hir().local_def_id(item_id); + let item_def_id = self.tcx.hir().body_owner_def_id(body.id()); // This attribute causes us to dump some writeback information // in the form of errors, which is used for unit tests. @@ -55,7 +54,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { - wbcx.visit_node_id(body.value.span, item_id); + let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); + wbcx.visit_node_id(body.value.span, item_hir_id); } hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), } @@ -545,6 +545,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); self.typeck_results.generator_interior_types = fcx_typeck_results.generator_interior_types.clone(); + for (&expr_def_id, predicates) in fcx_typeck_results.generator_interior_predicates.iter() { + let predicates = self.resolve(predicates.clone(), &self.fcx.tcx.def_span(expr_def_id)); + self.typeck_results.generator_interior_predicates.insert(expr_def_id, predicates); + } } #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 33a9a0cabb9..6703d53f380 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -38,7 +38,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; use rustc_graphviz as dot; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, @@ -74,7 +74,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let (if_this_changed, then_this_would_need) = { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; - visitor.process_attrs(hir::CRATE_HIR_ID); + visitor.process_attrs(CRATE_DEF_ID); tcx.hir().visit_all_item_likes_in_crate(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -119,9 +119,9 @@ impl<'tcx> IfThisChanged<'tcx> { value } - fn process_attrs(&mut self, hir_id: hir::HirId) { - let def_id = self.tcx.hir().local_def_id(hir_id); + fn process_attrs(&mut self, def_id: LocalDefId) { let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id()); + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { if attr.has_name(sym::rustc_if_this_changed) { @@ -180,22 +180,22 @@ impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - self.process_attrs(item.hir_id()); + self.process_attrs(item.owner_id.def_id); intravisit::walk_item(self, item); } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - self.process_attrs(trait_item.hir_id()); + self.process_attrs(trait_item.owner_id.def_id); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - self.process_attrs(impl_item.hir_id()); + self.process_attrs(impl_item.owner_id.def_id); intravisit::walk_impl_item(self, impl_item); } fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { - self.process_attrs(s.hir_id); + self.process_attrs(s.def_id); intravisit::walk_field_def(self, s); } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 091635e6c73..87c6dfad5fa 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -435,6 +435,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index e59715b706b..f7e3e4a1cc0 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -26,7 +26,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari use rustc_index::vec::IndexVec; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, List}; +use rustc_middle::ty::{self, List}; use rustc_span::source_map::Span; pub use rustc_middle::infer::canonical::*; @@ -87,12 +87,13 @@ impl<'tcx> InferCtxt<'tcx> { variables: &List<CanonicalVarInfo<'tcx>>, universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables - .iter() - .map(|info| self.instantiate_canonical_var(span, info, &universe_map)) - .collect(); - - CanonicalVarValues { var_values } + CanonicalVarValues { + var_values: self.tcx.mk_substs( + variables + .iter() + .map(|info| self.instantiate_canonical_var(span, info, &universe_map)), + ), + } } /// Given the "info" about a canonical variable, creates a fresh diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3d49182f0b8..3e8e7734a5a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -17,7 +17,7 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{PredicateObligations, TraitEngine}; +use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; @@ -482,11 +482,8 @@ impl<'tcx> InferCtxt<'tcx> { // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let result_subst = CanonicalVarValues { - var_values: query_response - .variables - .iter() - .enumerate() - .map(|(index, info)| { + var_values: self.tcx.mk_substs(query_response.variables.iter().enumerate().map( + |(index, info)| { if info.is_existential() { match opt_values[BoundVar::new(index)] { Some(k) => k, @@ -499,8 +496,8 @@ impl<'tcx> InferCtxt<'tcx> { universe_map[u.as_usize()] }) } - }) - .collect(), + }, + )), }; let mut obligations = vec![]; diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 389afe22eb7..e77f2d37b7d 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -72,16 +72,15 @@ where value } else { let delegate = FnMutDelegate { - regions: &mut |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { + regions: &mut |br: ty::BoundRegion| match var_values[br.var].unpack() { GenericArgKind::Lifetime(l) => l, r => bug!("{:?} is a region but value is {:?}", br, r), }, - types: &mut |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { + types: &mut |bound_ty: ty::BoundTy| match var_values[bound_ty.var].unpack() { GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), }, - consts: &mut |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() - { + consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() { GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 72676b718fa..a567b6acdbe 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -37,7 +37,10 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{ + self, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeVisitable, +}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -140,8 +143,6 @@ impl<'tcx> InferCtxt<'tcx> { let a = self.shallow_resolve(a); let b = self.shallow_resolve(b); - let a_is_expected = relation.a_is_expected(); - match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), @@ -158,11 +159,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); + return self.unify_const_variable(vid, b); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); + return self.unify_const_variable(vid, a); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { // FIXME(#59490): Need to remove the leak check to accommodate @@ -223,10 +224,8 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn unify_const_variable( &self, - param_env: ty::ParamEnv<'tcx>, target_vid: ty::ConstVid<'tcx>, ct: ty::Const<'tcx>, - vid_is_expected: bool, ) -> RelateResult<'tcx, ty::Const<'tcx>> { let (for_universe, span) = { let mut inner = self.inner.borrow_mut(); @@ -239,8 +238,12 @@ impl<'tcx> InferCtxt<'tcx> { ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), } }; - let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid } - .relate(ct, ct)?; + let value = ct.try_fold_with(&mut ConstInferUnifier { + infcx: self, + span, + for_universe, + target_vid, + })?; self.inner.borrow_mut().const_unification_table().union_value( target_vid, @@ -800,8 +803,6 @@ struct ConstInferUnifier<'cx, 'tcx> { span: Span, - param_env: ty::ParamEnv<'tcx>, - for_universe: ty::UniverseIndex, /// The vid of the const variable that is in the process of being @@ -810,61 +811,15 @@ struct ConstInferUnifier<'cx, 'tcx> { target_vid: ty::ConstVid<'tcx>, } -// We use `TypeRelation` here to propagate `RelateResult` upwards. -// -// Both inputs are expected to be the same. -impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn intercrate(&self) -> bool { - assert!(!self.infcx.intercrate); - false - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "ConstInferUnifier" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn mark_ambiguous(&mut self) { - bug!() - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - _variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - // We don't care about variance here. - self.relate(a, b) - } +impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> { + type Error = TypeError<'tcx>; - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.infcx.tcx } #[instrument(level = "debug", skip(self), ret)] - fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug_assert_eq!(t, _t); - + fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> { match t.kind() { &ty::Infer(ty::TyVar(vid)) => { let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); @@ -872,7 +827,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { match probe { TypeVariableValue::Known { value: u } => { debug!("ConstOccursChecker: known value {:?}", u); - self.tys(u, u) + u.try_fold_with(self) } TypeVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { @@ -892,16 +847,15 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), - _ => relate::super_relate_tys(self, t, t), + _ => t.try_super_fold_with(self), } } - fn regions( + #[instrument(level = "debug", skip(self), ret)] + fn try_fold_region( &mut self, r: ty::Region<'tcx>, - _r: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug_assert_eq!(r, _r); + ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> { debug!("ConstInferUnifier: r={:?}", r); match *r { @@ -930,14 +884,8 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } - #[instrument(level = "debug", skip(self))] - fn consts( - &mut self, - c: ty::Const<'tcx>, - _c: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug_assert_eq!(c, _c); - + #[instrument(level = "debug", skip(self), ret)] + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> { match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { // Check if the current unification would end up @@ -958,7 +906,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let var_value = self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); match var_value.val { - ConstVariableValue::Known { value: u } => self.consts(u, u), + ConstVariableValue::Known { value: u } => u.try_fold_with(self), ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) @@ -977,17 +925,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; - - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) - } - _ => relate::super_relate_consts(self, c, c), + _ => c.try_super_fold_with(self), } } } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 8f53b1ccdf4..83d71edc2ab 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -209,6 +209,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::Foreign(..) | ty::Param(..) | ty::Closure(..) + | ty::GeneratorWitnessMIR(..) | ty::GeneratorWitness(..) => t.super_fold_with(self), ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t), diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 21b68ce9989..b92b162a978 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(Box::new(self.fields.trace.clone())); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( + // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( self.tcx(), origin, a, diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index c07ac1d3ace..f6e0554fd1f 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -79,7 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = Subtype(Box::new(self.fields.trace.clone())); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( + // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 + Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( self.tcx(), origin, a, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index f235cb5ab45..f83219b8ee2 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -663,13 +663,13 @@ where debug!(?v_b); if self.ambient_covariance() { - // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a, self.ambient_variance_info); + // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. + self.push_outlives(v_a, v_b, self.ambient_variance_info); } if self.ambient_contravariance() { - // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b, self.ambient_variance_info); + // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. + self.push_outlives(v_b, v_a, self.ambient_variance_info); } Ok(a) diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 3d86279b03c..e3d95669171 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -112,7 +112,7 @@ fn compute_components<'tcx>( } // All regions are bound inside a witness - ty::GeneratorWitness(..) => (), + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => (), // OutlivesTypeParameterEnv -- the actual checking that `X:'a` // is implied by the environment is done in regionck. diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index bd38b52ba34..51c34f0d55f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -191,12 +191,13 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { // from the "cause" field, we could perhaps give more tailored // error messages. let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) self.fields .infcx .inner .borrow_mut() .unwrap_region_constraints() - .make_subregion(origin, a, b); + .make_subregion(origin, b, a); Ok(a) } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index fcde00056cb..f75344f20b6 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -36,11 +36,19 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>; + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; + + /// Among all pending obligations, collect those are stalled on a inference variable which has + /// changed since the last call to `select_where_possible`. Those obligations are marked as + /// successful and returned. + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>>; } pub trait TraitEngineExt<'tcx> { @@ -49,6 +57,8 @@ pub trait TraitEngineExt<'tcx> { infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, ); + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; } impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { @@ -61,4 +71,13 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { self.register_predicate_obligation(infcx, obligation); } } + + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { + let errors = self.select_where_possible(infcx); + if !errors.is_empty() { + return errors; + } + + self.collect_remaining_errors() + } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 37b381c534e..60b60edd2c8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -893,6 +893,15 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } }); + if tcx.sess.opts.unstable_opts.drop_tracking_mir { + tcx.hir().par_body_owners(|def_id| { + if let rustc_hir::def::DefKind::Generator = tcx.def_kind(def_id) { + tcx.ensure().mir_generator_witnesses(def_id); + tcx.ensure().check_generator_obligations(def_id); + } + }); + } + sess.time("layout_testing", || layout_test::test_layout(tcx)); // Avoid overwhelming user with errors if borrow checking failed. diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index f27fd90c55c..8361c81f0ef 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -56,9 +56,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{ - Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin, -}; +use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -583,12 +581,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { // If the method is an impl for a trait, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl { + let context = method_context(cx, impl_item.owner_id.def_id); + if context == MethodLateContext::TraitImpl { return; } // If the method is an impl for an item with docs_hidden, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl { + if context == MethodLateContext::PlainImpl { let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); let impl_ty = cx.tcx.type_of(parent); let outerdef = match impl_ty.kind() { @@ -1296,19 +1295,18 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { _: &'tcx FnDecl<'_>, _: &'tcx Body<'_>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller - && let attrs = cx.tcx.hir().attrs(hir_id) // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) - { - cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { - label: span, - parse_sess: &cx.tcx.sess.parse_sess, - }); - } + && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + { + cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }); + } } } @@ -2175,13 +2173,31 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { dropped_predicate_count += 1; } - if drop_predicate && !in_where_clause { - lint_spans.push(predicate_span); - } else if drop_predicate && i + 1 < num_predicates { - // If all the bounds on a predicate were inferable and there are - // further predicates, we want to eat the trailing comma. - let next_predicate_span = hir_generics.predicates[i + 1].span(); - where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo())); + if drop_predicate { + if !in_where_clause { + lint_spans.push(predicate_span); + } else if predicate_span.from_expansion() { + // Don't try to extend the span if it comes from a macro expansion. + where_lint_spans.push(predicate_span); + } else if i + 1 < num_predicates { + // If all the bounds on a predicate were inferable and there are + // further predicates, we want to eat the trailing comma. + let next_predicate_span = hir_generics.predicates[i + 1].span(); + if next_predicate_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans + .push(predicate_span.to(next_predicate_span.shrink_to_lo())); + } + } else { + // Eat the optional trailing comma after the last predicate. + let where_span = hir_generics.where_clause_span; + if where_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi())); + } + } } else { where_lint_spans.extend(self.consolidate_outlives_bound_spans( predicate_span.shrink_to_lo(), @@ -2225,6 +2241,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Applicability::MaybeIncorrect }; + // Due to macros, there might be several predicates with the same span + // and we only want to suggest removing them once. + lint_spans.sort_unstable(); + lint_spans.dedup(); + cx.emit_spanned_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), @@ -2661,7 +2682,7 @@ pub struct ClashingExternDeclarations { /// the symbol should be reported as a clashing declaration. // FIXME: Technically, we could just store a &'tcx str here without issue; however, the // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. - seen_decls: FxHashMap<Symbol, HirId>, + seen_decls: FxHashMap<Symbol, hir::OwnerId>, } /// Differentiate between whether the name for an extern decl came from the link_name attribute or @@ -2687,19 +2708,20 @@ impl ClashingExternDeclarations { pub(crate) fn new() -> Self { ClashingExternDeclarations { seen_decls: FxHashMap::default() } } + /// Insert a new foreign item into the seen set. If a symbol with the same name already exists /// for the item, return its HirId without updating the set. - fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> { + fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> { let did = fi.owner_id.to_def_id(); let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); - if let Some(&hir_id) = self.seen_decls.get(&name) { + if let Some(&existing_id) = self.seen_decls.get(&name) { // Avoid updating the map with the new entry when we do find a collision. We want to // make sure we're always pointing to the first definition as the previous declaration. // This lets us avoid emitting "knock-on" diagnostics. - Some(hir_id) + Some(existing_id) } else { - self.seen_decls.insert(name, fi.hir_id()) + self.seen_decls.insert(name, fi.owner_id) } } @@ -2926,16 +2948,16 @@ impl ClashingExternDeclarations { impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]); impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { + #[instrument(level = "trace", skip(self, cx))] fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) { - trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi); if let ForeignItemKind::Fn(..) = this_fi.kind { let tcx = cx.tcx; - if let Some(existing_hid) = self.insert(tcx, this_fi) { - let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); + if let Some(existing_did) = self.insert(tcx, this_fi) { + let existing_decl_ty = tcx.type_of(existing_did); let this_decl_ty = tcx.type_of(this_fi.owner_id); debug!( "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", - existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty + existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty ); // Check that the declarations match. if !Self::structurally_same_type( @@ -2944,7 +2966,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { this_decl_ty, CItemKind::Declaration, ) { - let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner()); + let orig_fi = tcx.hir().expect_foreign_item(existing_did); let orig = Self::name_of_extern_decl(tcx, orig_fi); // We want to ensure that we use spans for both decls that include where the diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b2a2656746e..b42878a02ee 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -66,13 +66,12 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { self.context.last_node_with_lint_attrs = prev; } - fn with_param_env<F>(&mut self, id: hir::HirId, f: F) + fn with_param_env<F>(&mut self, id: hir::OwnerId, f: F) where F: FnOnce(&mut Self), { let old_param_env = self.context.param_env; - self.context.param_env = - self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id)); + self.context.param_env = self.context.tcx.param_env(id); f(self); self.context.param_env = old_param_env; } @@ -132,7 +131,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let old_cached_typeck_results = self.context.cached_typeck_results.take(); let old_enclosing_body = self.context.enclosing_body.take(); self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_item, it); hir_visit::walk_item(cx, it); lint_callback!(cx, check_item_post, it); @@ -145,7 +144,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_foreign_item, it); hir_visit::walk_foreign_item(cx, it); }); @@ -180,7 +179,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas decl: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, span: Span, - id: hir::HirId, + id: LocalDefId, ) { // Wrap in typeck results here, not just in visit_nested_body, // in order for `check_fn` to be able to use them. @@ -268,7 +267,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&trait_item.generics); self.with_lint_attrs(trait_item.hir_id(), |cx| { - cx.with_param_env(trait_item.hir_id(), |cx| { + cx.with_param_env(trait_item.owner_id, |cx| { lint_callback!(cx, check_trait_item, trait_item); hir_visit::walk_trait_item(cx, trait_item); }); @@ -280,7 +279,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&impl_item.generics); self.with_lint_attrs(impl_item.hir_id(), |cx| { - cx.with_param_env(impl_item.hir_id(), |cx| { + cx.with_param_env(impl_item.owner_id, |cx| { lint_callback!(cx, check_impl_item, impl_item); hir_visit::walk_impl_item(cx, impl_item); lint_callback!(cx, check_impl_item_post, impl_item); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 74d234fabea..71e2e66bdeb 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -10,8 +10,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; use rustc_hir::{GenericParamKind, PatKind}; use rustc_middle::ty; -use rustc_span::symbol::sym; -use rustc_span::{symbol::Ident, BytePos, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; #[derive(PartialEq)] @@ -21,9 +22,8 @@ pub enum MethodLateContext { PlainImpl, } -pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext { - let def_id = cx.tcx.hir().local_def_id(id); - let item = cx.tcx.associated_item(def_id); +pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext { + let item = cx.tcx.associated_item(id); match item.container { ty::TraitContainer => MethodLateContext::TraitAutoImpl, ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) { @@ -379,13 +379,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { _: &hir::FnDecl<'_>, _: &hir::Body<'_>, _: Span, - id: hir::HirId, + id: LocalDefId, ) { - let attrs = cx.tcx.hir().attrs(id); match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) + if sig.header.abi != Abi::Rust + && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } @@ -398,7 +398,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 0bf01c4e567..16964565b01 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -4,6 +4,7 @@ use rustc_ast as ast; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -36,7 +37,7 @@ macro_rules! late_lint_methods { b: &'tcx hir::FnDecl<'tcx>, c: &'tcx hir::Body<'tcx>, d: Span, - e: hir::HirId); + e: LocalDefId); fn check_trait_item(a: &'tcx hir::TraitItem<'tcx>); fn check_impl_item(a: &'tcx hir::ImplItem<'tcx>); fn check_impl_item_post(a: &'tcx hir::ImplItem<'tcx>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9be4b577aeb..b0a5d3674ad 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -14,6 +14,7 @@ use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -1107,6 +1108,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Placeholder(..) | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), } @@ -1223,8 +1225,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) { - let def_id = self.cx.tcx.hir().local_def_id(id); + fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) { let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); let sig = self.cx.tcx.erase_late_bound_regions(sig); @@ -1238,9 +1239,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { - let def_id = self.cx.tcx.hir().local_def_id(id); - let ty = self.cx.tcx.type_of(def_id); + fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) { + let ty = self.cx.tcx.type_of(id); self.check_type_for_ffi_and_report_errors(span, ty, true, false); } @@ -1260,10 +1260,10 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { if !vis.is_internal_abi(abi) { match it.kind { hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(it.hir_id(), decl); + vis.check_foreign_fn(it.owner_id.def_id, decl); } hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(it.hir_id(), ty.span); + vis.check_foreign_static(it.owner_id, ty.span); } hir::ForeignItemKind::Type => (), } @@ -1279,7 +1279,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { decl: &'tcx hir::FnDecl<'_>, _: &'tcx hir::Body<'_>, _: Span, - hir_id: hir::HirId, + id: LocalDefId, ) { use hir::intravisit::FnKind; @@ -1291,7 +1291,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; if !vis.is_internal_abi(abi) { - vis.check_foreign_fn(hir_id, decl); + vis.check_foreign_fn(id, decl); } } } diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs index 32338f9dfc5..08098c9bb2a 100644 --- a/compiler/rustc_macros/src/diagnostics/fluent.rs +++ b/compiler/rustc_macros/src/diagnostics/fluent.rs @@ -4,7 +4,10 @@ use annotate_snippets::{ }; use fluent_bundle::{FluentBundle, FluentError, FluentResource}; use fluent_syntax::{ - ast::{Attribute, Entry, Identifier, Message}, + ast::{ + Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, + PatternElement, + }, parser::ParserError, }; use proc_macro::{Diagnostic, Level, Span}; @@ -185,9 +188,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok }; let mut constants = TokenStream::new(); + let mut messagerefs = Vec::new(); for entry in resource.entries() { let span = res.krate.span(); - if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry { + if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = + entry + { let _ = previous_defns.entry(name.to_string()).or_insert(path_span); if name.contains('-') { @@ -200,6 +206,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok .emit(); } + if let Some(Pattern { elements }) = value { + for elt in elements { + if let PatternElement::Placeable { + expression: + Expression::Inline(InlineExpression::MessageReference { id, .. }), + } = elt + { + messagerefs.push((id.name, *name)); + } + } + } + // Require that the message name starts with the crate name // `hir_typeck_foo_bar` (in `hir_typeck.ftl`) // `const_eval_baz` (in `const_eval.ftl`) @@ -258,6 +276,18 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok } } + for (mref, name) in messagerefs.into_iter() { + if !previous_defns.contains_key(mref) { + Diagnostic::spanned( + path_span, + Level::Error, + format!("referenced message `{mref}` does not exist (in message `{name}`)"), + ) + .help(&format!("you may have meant to use a variable reference (`{{${mref}}}`)")) + .emit(); + } + } + if let Err(errs) = bundle.add_resource(resource) { for e in errs { match e { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index e5d0bb87edf..9b1401f4a44 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -202,6 +202,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + mir_generator_witnesses => { table } promoted_mir => { table } def_span => { table } def_ident_span => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f46050dedc2..29507ff3a86 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1310,8 +1310,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemKind::Struct(ref vdata, _) => { yield item_id.owner_id.def_id.local_def_index; // Encode constructors which take a separate slot in value namespace. - if let Some(ctor_hir_id) = vdata.ctor_hir_id() { - yield tcx.hir().local_def_id(ctor_hir_id).local_def_index; + if let Some(ctor_def_id) = vdata.ctor_def_id() { + yield ctor_def_id.local_def_index; } } _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => { @@ -1414,6 +1414,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + + if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir { + record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id)); + } } if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index cf735e5bd17..37af9e64e9a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -376,6 +376,7 @@ define_tables! { object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>, optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>, mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, + mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, // FIXME(compiler-errors): Why isn't this a LazyArray? thir_abstract_const: Table<DefIndex, LazyValue<ty::Const<'static>>>, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f816d614500..72f4f6e649b 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -105,7 +105,7 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>, - [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>, + [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::ItemLocalId>, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9e63c2bd221..5bd6b070442 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -18,24 +18,30 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; #[inline] -pub fn associated_body(node: Node<'_>) -> Option<BodyId> { +pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { match node { Node::Item(Item { + owner_id, kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body), .. }) | Node::TraitItem(TraitItem { + owner_id, kind: TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { + owner_id, kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), .. - }) - | Node::Expr(Expr { kind: ExprKind::Closure(Closure { body, .. }), .. }) => Some(*body), + }) => Some((owner_id.def_id, *body)), + + Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { + Some((*def_id, *body)) + } - Node::AnonConst(constant) => Some(constant.body), + Node::AnonConst(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -43,7 +49,7 @@ pub fn associated_body(node: Node<'_>) -> Option<BodyId> { fn is_body_owner(node: Node<'_>, hir_id: HirId) -> bool { match associated_body(node) { - Some(b) => b.hir_id == hir_id, + Some((_, b)) => b.hir_id == hir_id, None => false, } } @@ -154,10 +160,6 @@ impl<'hir> Map<'hir> { self.tcx.definitions_untracked().def_key(def_id) } - pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> { - self.opt_local_def_id(id).map(|def_id| self.def_path(def_id)) - } - pub fn def_path(self, def_id: LocalDefId) -> DefPath { // Accessing the DefPath is ok, since it is part of DefPathHash. self.tcx.definitions_untracked().def_path(def_id) @@ -170,32 +172,6 @@ impl<'hir> Map<'hir> { } #[inline] - #[track_caller] - pub fn local_def_id(self, hir_id: HirId) -> LocalDefId { - self.opt_local_def_id(hir_id).unwrap_or_else(|| { - bug!( - "local_def_id: no entry for `{:?}`, which has a map of `{:?}`", - hir_id, - self.find(hir_id) - ) - }) - } - - #[inline] - pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> { - if hir_id.local_id == ItemLocalId::new(0) { - Some(hir_id.owner.def_id) - } else { - self.tcx - .hir_owner_nodes(hir_id.owner) - .as_owner()? - .local_id_to_def_id - .get(&hir_id.local_id) - .copied() - } - } - - #[inline] pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId { self.tcx.local_def_id_to_hir_id(def_id) } @@ -410,8 +386,8 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn enclosing_body_owner(self, hir_id: HirId) -> LocalDefId { for (_, node) in self.parent_iter(hir_id) { - if let Some(body) = associated_body(node) { - return self.body_owner_def_id(body); + if let Some((def_id, _)) = associated_body(node) { + return def_id; } } @@ -427,14 +403,17 @@ impl<'hir> Map<'hir> { parent } - pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId { - self.local_def_id(self.body_owner(id)) + pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId { + let parent = self.parent_id(hir_id); + associated_body(self.get(parent)).unwrap().0 } /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> { - self.find_by_def_id(id).and_then(associated_body) + let node = self.find_by_def_id(id)?; + let (_, body_id) = associated_body(node)?; + Some(body_id) } /// Given a body owner's id, returns the `BodyId` associated with it. diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 43583b5723e..6e130bbf7d8 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -25,10 +25,8 @@ use crate::infer::MemberConstraint; use crate::mir::ConstraintCategory; use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; -use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use smallvec::SmallVec; -use std::iter; use std::ops::Index; /// A "canonicalized" type `V` is one where all free inference @@ -62,23 +60,23 @@ impl<'tcx> ty::TypeFoldable<'tcx> for CanonicalVarInfos<'tcx> { /// vectors with the original values that were replaced by canonical /// variables. You will need to supply it later to instantiate the /// canonicalized query response. -#[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>, + pub var_values: ty::SubstsRef<'tcx>, } impl CanonicalVarValues<'_> { pub fn is_identity(&self) -> bool { - self.var_values.iter_enumerated().all(|(bv, arg)| match arg.unpack() { + self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { ty::GenericArgKind::Lifetime(r) => { - matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var == bv) + matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv) } ty::GenericArgKind::Type(ty) => { - matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var == bv) + matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) } ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc == bv) + matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) } }) } @@ -339,57 +337,57 @@ TrivialTypeTraversalAndLiftImpls! { } impl<'tcx> CanonicalVarValues<'tcx> { + // Given a list of canonical variables, construct a set of values which are + // the identity response. + pub fn make_identity( + tcx: TyCtxt<'tcx>, + infos: CanonicalVarInfos<'tcx>, + ) -> CanonicalVarValues<'tcx> { + CanonicalVarValues { + var_values: tcx.mk_substs(infos.iter().enumerate().map( + |(i, info)| -> ty::GenericArg<'tcx> { + match info.kind { + CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => tcx + .mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())) + .into(), + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(i), + kind: ty::BrAnon(i as u32, None), + }; + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() + } + CanonicalVarKind::Const(_, ty) + | CanonicalVarKind::PlaceholderConst(_, ty) => tcx + .mk_const( + ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), + ty, + ) + .into(), + } + }, + )), + } + } + /// Creates dummy var values which should not be used in a /// canonical response. pub fn dummy() -> CanonicalVarValues<'tcx> { - CanonicalVarValues { var_values: Default::default() } + CanonicalVarValues { var_values: ty::List::empty() } } #[inline] pub fn len(&self) -> usize { self.var_values.len() } - - /// Makes an identity substitution from this one: each bound var - /// is matched to the same bound var, preserving the original kinds. - /// For example, if we have: - /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]` - /// we'll return a substitution `subst` with: - /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`. - pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self { - use crate::ty::subst::GenericArgKind; - - CanonicalVarValues { - var_values: iter::zip(&self.var_values, 0..) - .map(|(kind, i)| match kind.unpack() { - GenericArgKind::Type(..) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() - } - GenericArgKind::Lifetime(..) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(i), - kind: ty::BrAnon(i, None), - }; - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() - } - GenericArgKind::Const(ct) => tcx - .mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), - ct.ty(), - ) - .into(), - }) - .collect(), - } - } } impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { type Item = GenericArg<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>; + type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>; fn into_iter(self) -> Self::IntoIter { - self.var_values.iter().cloned() + self.var_values.iter() } } @@ -397,6 +395,6 @@ impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> { type Output = GenericArg<'tcx>; fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { - &self.var_values[value] + &self.var_values[value.as_usize()] } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4da893e4c07..bc3c38fdb1c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -902,6 +902,8 @@ pub enum LocalInfo<'tcx> { AggregateTemp, /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, + /// A temporary created for borrow checking. + FakeBorrow, } impl<'tcx> LocalDecl<'tcx> { @@ -2504,7 +2506,7 @@ impl<'tcx> ConstantKind<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) { - if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) { + if let Some(parent_did) = parent_hir_id.as_owner() { InternalSubsts::identity_for_item(tcx, parent_did.to_def_id()) } else { tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter()) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a8a4532223c..6155f2bb56c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -135,11 +135,20 @@ rustc_index::newtype_index! { pub struct GeneratorSavedLocal {} } +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +pub struct GeneratorSavedTy<'tcx> { + pub ty: Ty<'tcx>, + /// Source info corresponding to the local in the original MIR body. + pub source_info: SourceInfo, + /// Whether the local should be ignored for trait bound computations. + pub ignore_for_traits: bool, +} + /// The layout of generator state. #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. - pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>, + pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>, /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 887ee571575..fb1e3d233a2 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -670,7 +670,7 @@ fn fn_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { fn hir_body(tcx: TyCtxt<'_>, def_id: DefId) -> Option<&rustc_hir::Body<'_>> { let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id)) + hir::map::associated_body(hir_node).map(|(_, fn_body_id)| tcx.hir().body(fn_body_id)) } fn escape_html(s: &str) -> String { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index dc626c2433c..460a5147766 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -471,6 +471,17 @@ rustc_queries! { } } + query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> { + arena_cache + desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + + query check_generator_obligations(key: LocalDefId) { + desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key.to_def_id()) } + } + /// MIR after our optimization passes have run. This is MIR that is ready /// for codegen. This is also the only query that can fetch non-local MIR, at present. query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> { @@ -1629,7 +1640,7 @@ rustc_queries! { Option<&'tcx FxHashMap<ItemLocalId, Region>> { desc { "looking up a named region" } } - query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> { + query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> { desc { "testing if a region is late bound" } } /// For a given item's generic parameter, gets the default lifetimes to be used diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f6fae8ab552..cf3dce48064 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -37,7 +37,7 @@ pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner /// Depending on the stage of compilation, we want projection to be /// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] pub enum Reveal { /// At type-checking time, we refuse to project any associated /// type that is marked `default`. Non-`default` ("final") types @@ -90,7 +90,8 @@ pub enum Reveal { /// /// We do not want to intern this as there are a lot of obligation causes which /// only live for a short period of time. -#[derive(Clone, Debug, PartialEq, Eq, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -197,14 +198,16 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct UnifyReceiverContext<'tcx> { pub assoc_item: ty::AssocItem, pub param_env: ty::ParamEnv<'tcx>, pub substs: SubstsRef<'tcx>, } -#[derive(Clone, PartialEq, Eq, Hash, Lift, Default)] +#[derive(Clone, PartialEq, Eq, Hash, Lift, Default, HashStable)] +#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] pub struct InternedObligationCauseCode<'tcx> { /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of /// the time). `Some` otherwise. @@ -239,7 +242,8 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. MiscObligation, @@ -447,7 +451,8 @@ pub enum ObligationCauseCode<'tcx> { /// This information is used to obtain an `hir::Ty`, which /// we can walk in order to obtain precise spans for any /// 'nested' types (e.g. `Foo` in `Option<Foo>`). -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] +#[derive(TypeVisitable, TypeFoldable)] pub enum WellFormedLoc { /// Use the type of the provided definition. Ty(LocalDefId), @@ -464,7 +469,8 @@ pub enum WellFormedLoc { }, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct ImplDerivedObligationCause<'tcx> { pub derived: DerivedObligationCause<'tcx>, pub impl_def_id: DefId, @@ -518,7 +524,8 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct MatchExpressionArmCause<'tcx> { pub arm_block_id: Option<hir::HirId>, pub arm_ty: Ty<'tcx>, @@ -534,7 +541,7 @@ pub struct MatchExpressionArmCause<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(Lift, TypeFoldable, TypeVisitable)] +#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct IfExpressionCause<'tcx> { pub then_id: hir::HirId, pub else_id: hir::HirId, @@ -544,7 +551,8 @@ pub struct IfExpressionCause<'tcx> { pub opt_suggest_box_span: Option<Span>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] pub struct DerivedObligationCause<'tcx> { /// The trait predicate of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index d3d667f6840..099a7845118 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -188,7 +188,7 @@ impl<'tcx> AdtDef<'tcx> { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, Union, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8cc8286c1db..b9a1e23879c 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -157,6 +157,14 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> { + fn encode(&self, e: &mut E) { + self.caller_bounds().encode(e); + self.reveal().encode(e); + self.constness().encode(e); + } +} + #[inline] fn decode_arena_allocable< 'tcx, @@ -280,8 +288,17 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::ParamEnv<'tcx> { + fn decode(d: &mut D) -> Self { + let caller_bounds = Decodable::decode(d); + let reveal = Decodable::decode(d); + let constness = Decodable::decode(d); + ty::ParamEnv::new(caller_bounds, reveal, constness) + } +} + macro_rules! impl_decodable_via_ref { - ($($t:ty),+) => { + ($($t:ty,)+) => { $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t { fn decode(decoder: &mut D) -> Self { RefDecodable::decode(decoder) @@ -373,6 +390,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + let predicates: Vec<_> = + (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)).collect(); + decoder.interner().intern_predicates(&predicates) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List<Ty<'tcx>>, @@ -382,7 +408,8 @@ impl_decodable_via_ref! { &'tcx mir::UnsafetyCheckResult, &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, - &'tcx ty::List<ty::BoundVariableKind> + &'tcx ty::List<ty::BoundVariableKind>, + &'tcx ty::List<ty::Predicate<'tcx>>, } #[macro_export] @@ -519,6 +546,8 @@ macro_rules! impl_binder_encode_decode { impl_binder_encode_decode! { &'tcx ty::List<Ty<'tcx>>, ty::FnSig<'tcx>, + ty::Predicate<'tcx>, + ty::TraitPredicate<'tcx>, ty::ExistentialPredicate<'tcx>, ty::TraitRef<'tcx>, Vec<ty::GeneratorInteriorTypeCause<'tcx>>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a60c55e8af4..526df090a3c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1306,6 +1306,7 @@ impl<'tcx> TyCtxt<'tcx> { Placeholder, Generator, GeneratorWitness, + GeneratorWitnessMIR, Dynamic, Closure, Tuple, @@ -1816,6 +1817,11 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] + pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + self.mk_ty(GeneratorWitnessMIR(id, substs)) + } + + #[inline] pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { self.mk_ty_infer(TyVar(v)) } @@ -2151,10 +2157,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner.def_id).map_or(false, |set| { - let def_id = self.hir().local_def_id(id); - set.contains(&def_id) - }) + self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id)) } pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index c8a700c4e28..d83fc95ac4e 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -325,7 +325,8 @@ impl<'tcx> Ty<'tcx> { ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), - ty::GeneratorWitness(..) => "generator witness".into(), + ty::GeneratorWitness(..) | + ty::GeneratorWitnessMIR(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integer".into(), @@ -373,7 +374,7 @@ impl<'tcx> Ty<'tcx> { ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(), - ty::GeneratorWitness(..) => "generator witness".into(), + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => "generator witness".into(), ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), ty::Bound(..) => "bound type variable".into(), diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index f785fb5c4b9..9afa37e9ef3 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -32,6 +32,7 @@ pub enum SimplifiedType { ClosureSimplifiedType(DefId), GeneratorSimplifiedType(DefId), GeneratorWitnessSimplifiedType(usize), + GeneratorWitnessMIRSimplifiedType(DefId), FunctionSimplifiedType(usize), PlaceholderSimplifiedType, } @@ -108,6 +109,7 @@ pub fn simplify_type<'tcx>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())), + ty::GeneratorWitnessMIR(def_id, _) => Some(GeneratorWitnessMIRSimplifiedType(def_id)), ty::Never => Some(NeverSimplifiedType), ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())), ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), @@ -139,7 +141,8 @@ impl SimplifiedType { | ForeignSimplifiedType(d) | TraitSimplifiedType(d) | ClosureSimplifiedType(d) - | GeneratorSimplifiedType(d) => Some(d), + | GeneratorSimplifiedType(d) + | GeneratorWitnessMIRSimplifiedType(d) => Some(d), _ => None, } } @@ -208,6 +211,7 @@ impl DeepRejectCtxt { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), @@ -306,7 +310,7 @@ impl DeepRejectCtxt { ty::Error(_) => true, - ty::GeneratorWitness(..) | ty::Bound(..) => { + ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Bound(..) => { bug!("unexpected obligation type: {:?}", obligation_ty) } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index b7eafc4b437..dc6f5851b7d 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -125,6 +125,16 @@ impl FlagComputation { self.bound_computation(ts, |flags, ts| flags.add_tys(ts)); } + &ty::GeneratorWitnessMIR(_, ref substs) => { + let should_remove_further_specializable = + !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); + self.add_substs(substs); + if should_remove_further_specializable { + self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; + } + self.add_flags(TypeFlags::HAS_TY_GENERATOR); + } + &ty::Closure(_, substs) => { let substs = substs.as_closure(); let should_remove_further_specializable = diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 66b9d96e695..cdcd6281f20 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -645,6 +645,7 @@ where | ty::Never | ty::FnDef(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Foreign(..) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4af29fcbfb5..7001f81aa77 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -31,7 +31,6 @@ pub use generics::*; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -453,18 +452,6 @@ pub struct CReaderCacheKey { #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>); -impl<'tcx> TyCtxt<'tcx> { - /// A "bool" type used in rustc_mir_transform unit tests when we - /// have not spun up a TyCtxt. - pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = - Ty(Interned::new_unchecked(&WithCachedTypeInfo { - internee: ty::Bool, - stable_hash: Fingerprint::ZERO, - flags: TypeFlags::empty(), - outer_exclusive_binder: DebruijnIndex::from_usize(0), - })); -} - impl ty::EarlyBoundRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 98cd92007c2..7ff58f02623 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -3,6 +3,7 @@ use crate::ty::fold::{TypeFolder, TypeSuperFoldable}; use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; +use rustc_span::def_id::DefId; use rustc_span::Span; /// Converts generic params of a TypeFoldable from one @@ -47,6 +48,47 @@ impl<'tcx> ReverseMapper<'tcx> { assert!(!self.do_not_error); kind.fold_with(self) } + + fn fold_closure_substs( + &mut self, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, + ) -> ty::SubstsRef<'tcx> { + // I am a horrible monster and I pray for death. When + // we encounter a closure here, it is always a closure + // from within the function that we are currently + // type-checking -- one that is now being encapsulated + // in an opaque type. Ideally, we would + // go through the types/lifetimes that it references + // and treat them just like we would any other type, + // which means we would error out if we find any + // reference to a type/region that is not in the + // "reverse map". + // + // **However,** in the case of closures, there is a + // somewhat subtle (read: hacky) consideration. The + // problem is that our closure types currently include + // all the lifetime parameters declared on the + // enclosing function, even if they are unused by the + // closure itself. We can't readily filter them out, + // so here we replace those values with `'empty`. This + // can't really make a difference to the rest of the + // compiler; those regions are ignored for the + // outlives relation, and hence don't affect trait + // selection or auto traits, and they are erased + // during codegen. + + let generics = self.tcx.generics_of(def_id); + self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_no_missing_regions_error(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + })) + } } impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { @@ -104,59 +146,20 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match *ty.kind() { ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - + let substs = self.fold_closure_substs(def_id, substs); self.tcx.mk_closure(def_id, substs) } ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_no_missing_regions_error(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - + let substs = self.fold_closure_substs(def_id, substs); self.tcx.mk_generator(def_id, substs, movability) } + ty::GeneratorWitnessMIR(def_id, substs) => { + let substs = self.fold_closure_substs(def_id, substs); + self.tcx.mk_generator_witness_mir(def_id, substs) + } + ty::Param(param) => { // Look it up in the substitution list. match self.map.get(&ty.into()).map(|k| k.unpack()) { diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 24f3d1acff1..84edb5f2a42 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -117,6 +117,7 @@ macro_rules! parameterized_over_tcx { parameterized_over_tcx! { crate::middle::exported_symbols::ExportedSymbol, crate::mir::Body, + crate::mir::GeneratorLayout, ty::Ty, ty::FnSig, ty::GenericPredicates, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index c302c461195..90bf3288ccf 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -265,6 +265,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::Generator(def_id, _, _) + | ty::GeneratorWitnessMIR(def_id, _) | ty::Foreign(def_id) => Some(def_id), ty::Bool diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2f30dbebbc2..f2abec216b7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -811,6 +811,28 @@ pub trait PrettyPrinter<'tcx>: ty::GeneratorWitness(types) => { p!(in_binder(&types)); } + ty::GeneratorWitnessMIR(did, substs) => { + p!(write("[")); + if !self.tcx().sess.verbose() { + p!("generator witness"); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let span = self.tcx().def_span(did); + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_embeddable_string(span) + )); + } else { + p!(write("@"), print_def_path(did, substs)); + } + } else { + p!(print_def_path(did, substs)); + } + + p!("]") + } ty::Closure(did, substs) => { p!(write("[")); if !self.should_print_verbose() { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 28b9bdf5660..1be819ca610 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -118,6 +118,7 @@ fn copy<T: Copy>(x: &T) -> T { macro_rules! query_helper_param_ty { (DefId) => { impl IntoQueryParam<DefId> }; + (LocalDefId) => { impl IntoQueryParam<LocalDefId> }; ($K:ty) => { $K }; } @@ -418,6 +419,13 @@ mod sealed { } } + impl IntoQueryParam<LocalDefId> for OwnerId { + #[inline(always)] + fn into_query_param(self) -> LocalDefId { + self.def_id + } + } + impl IntoQueryParam<DefId> for LocalDefId { #[inline(always)] fn into_query_param(self) -> DefId { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 65fd8d9753d..fa87301df7e 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( if a_repr == b_repr => { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { - relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_region, - b_region, - ) + relation.relate(a_region, b_region) })?; Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } @@ -473,6 +468,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(tcx.mk_generator_witness(types)) } + (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs)) + if a_id == b_id => + { + // All GeneratorWitness types with the same id represent + // the (anonymous) type of the same generator expression. So + // all of their regions should be equated. + let substs = relation.relate(a_substs, b_substs)?; + Ok(tcx.mk_generator_witness_mir(a_id, substs)) + } + (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So @@ -487,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - let r = relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_r, - b_r, - )?; + let r = relation.relate(a_r, b_r)?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 2de886a3e81..034aab0c38e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -201,6 +201,7 @@ TrivialTypeTraversalAndLiftImpls! { bool, usize, ::rustc_target::abi::VariantIdx, + u16, u32, u64, String, @@ -655,6 +656,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Generator(did, substs.try_fold_with(folder)?, movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.try_fold_with(folder)?), + ty::GeneratorWitnessMIR(did, substs) => { + ty::GeneratorWitnessMIR(did, substs.try_fold_with(folder)?) + } ty::Closure(did, substs) => ty::Closure(did, substs.try_fold_with(folder)?), ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), @@ -700,6 +704,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), ty::GeneratorWitness(ref types) => types.visit_with(visitor), + ty::GeneratorWitnessMIR(_did, ref substs) => substs.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0656c77d0b5..f97d2e753a3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -571,9 +571,9 @@ impl<'tcx> GeneratorSubsts<'tcx> { ) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { - variant - .iter() - .map(move |field| ty::EarlyBinder(layout.field_tys[*field]).subst(tcx, self.substs)) + variant.iter().map(move |field| { + ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs) + }) }) } @@ -2175,6 +2175,7 @@ impl<'tcx> Ty<'tcx> { | ty::Dynamic(..) | ty::Closure(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Error(_) @@ -2210,6 +2211,7 @@ impl<'tcx> Ty<'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2296,6 +2298,7 @@ impl<'tcx> Ty<'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2360,7 +2363,7 @@ impl<'tcx> Ty<'tcx> { // anything with custom metadata it might be more complicated. ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, - ty::Generator(..) | ty::GeneratorWitness(..) => false, + ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => false, // Might be, but not "trivial" so just giving the safe answer. ty::Adt(..) | ty::Closure(..) => false, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 2902c6dc556..79a6c730d71 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -1,6 +1,7 @@ use crate::{ hir::place::Place as HirPlace, infer::canonical::Canonical, + traits::ObligationCause, ty::{ self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts, @@ -193,6 +194,11 @@ pub struct TypeckResults<'tcx> { /// that are live across the yield of this generator (if a generator). pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>, + /// Stores the predicates that apply on generator witness types. + /// formatting modified file tests/ui/generator/retain-resume-ref.rs + pub generator_interior_predicates: + FxHashMap<LocalDefId, Vec<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>>, + /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. /// This hashset records all instances where we behave @@ -271,6 +277,7 @@ impl<'tcx> TypeckResults<'tcx> { closure_fake_reads: Default::default(), rvalue_scopes: Default::default(), generator_interior_types: ty::Binder::dummy(Default::default()), + generator_interior_predicates: Default::default(), treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 54ea63bb4cf..796164b0d6a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -615,6 +615,36 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Return the set of types that should be taken into accound when checking + /// trait bounds on a generator's internal state. + pub fn generator_hidden_types( + self, + def_id: DefId, + ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> { + let generator_layout = &self.mir_generator_witnesses(def_id); + generator_layout + .field_tys + .iter() + .filter(|decl| !decl.ignore_for_traits) + .map(|decl| ty::EarlyBinder(decl.ty)) + } + + /// Normalizes all opaque types in the given value, replacing them + /// with their underlying types. + pub fn expand_opaque_types(self, val: Ty<'tcx>) -> Ty<'tcx> { + let mut visitor = OpaqueTypeExpander { + seen_opaque_tys: FxHashSet::default(), + expanded_cache: FxHashMap::default(), + primary_def_id: None, + found_recursion: false, + found_any_recursion: false, + check_recursion: false, + expand_generators: false, + tcx: self, + }; + val.fold_with(&mut visitor) + } + /// Expands the given impl trait type, stopping if the type is recursive. #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( @@ -629,6 +659,7 @@ impl<'tcx> TyCtxt<'tcx> { found_recursion: false, found_any_recursion: false, check_recursion: true, + expand_generators: true, tcx: self, }; @@ -741,6 +772,7 @@ struct OpaqueTypeExpander<'tcx> { primary_def_id: Option<DefId>, found_recursion: bool, found_any_recursion: bool, + expand_generators: bool, /// Whether or not to check for recursive opaque types. /// This is `true` when we're explicitly checking for opaque type /// recursion, and 'false' otherwise to avoid unnecessary work. @@ -777,6 +809,37 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { None } } + + fn expand_generator(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> { + if self.found_any_recursion { + return None; + } + let substs = substs.fold_with(self); + if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { + let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { + Some(expanded_ty) => *expanded_ty, + None => { + for bty in self.tcx.generator_hidden_types(def_id) { + let hidden_ty = bty.subst(self.tcx, substs); + self.fold_ty(hidden_ty); + } + let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs); + self.expanded_cache.insert((def_id, substs), expanded_ty); + expanded_ty + } + }; + if self.check_recursion { + self.seen_opaque_tys.remove(&def_id); + } + Some(expanded_ty) + } else { + // If another opaque type that we contain is recursive, then it + // will report the error, so we don't have to. + self.found_any_recursion = true; + self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); + None + } + } } impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { @@ -785,13 +848,19 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() { + let mut t = if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() { self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_opaque_types() { + } else if t.has_opaque_types() || t.has_generators() { t.super_fold_with(self) } else { t + }; + if self.expand_generators { + if let ty::GeneratorWitnessMIR(def_id, substs) = *t.kind() { + t = self.expand_generator(def_id, substs).unwrap_or(t); + } } + t } } @@ -896,6 +965,7 @@ impl<'tcx> Ty<'tcx> { | ty::Foreign(_) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Infer(_) | ty::Alias(..) | ty::Param(_) @@ -935,6 +1005,7 @@ impl<'tcx> Ty<'tcx> { | ty::Foreign(_) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Infer(_) | ty::Alias(..) | ty::Param(_) @@ -1062,7 +1133,10 @@ impl<'tcx> Ty<'tcx> { false } - ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false, + ty::Foreign(_) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Error(_) => false, } } @@ -1158,6 +1232,7 @@ pub fn needs_drop_components<'tcx>( | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str => Ok(SmallVec::new()), @@ -1228,7 +1303,11 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { // Not trivial because they have components, and instead of looking inside, // we'll just perform trait selection. - ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false, + ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) + | ty::Adt(..) => false, ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), @@ -1289,6 +1368,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>( found_recursion: false, found_any_recursion: false, check_recursion: false, + expand_generators: false, tcx, }; val.fold_with(&mut visitor) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index bee3cc4d7cb..d7b7a094737 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -100,6 +100,9 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { fn has_opaque_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } + fn has_generators(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_GENERATOR) + } fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 708a5e4d059..182945b9c3d 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -190,6 +190,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Adt(_, substs) | ty::Closure(_, substs) | ty::Generator(_, substs, _) + | ty::GeneratorWitnessMIR(_, substs) | ty::FnDef(_, substs) => { stack.extend(substs.iter().rev()); } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0961ce11e2f..6b960ebdb16 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1747,8 +1747,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); - let fake_borrow_temp = - self.local_decls.push(LocalDecl::new(fake_borrow_ty, temp_span)); + let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); + fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; + fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow)); + let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); (matched_place, fake_borrow_temp) }) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index b0d24af958d..ff88d001351 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -5,7 +5,6 @@ use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::Span; use rustc_trait_selection::traits::predicate_for_trait_def; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -190,11 +189,10 @@ impl<'tcx> ConstToPat<'tcx> { // using `PartialEq::eq` in this scenario in the past.) let partial_eq_trait_id = self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let def_id = self.tcx().hir().opt_local_def_id(self.id).unwrap_or(CRATE_DEF_ID); let obligation: PredicateObligation<'_> = predicate_for_trait_def( self.tcx(), self.param_env, - ObligationCause::misc(self.span, def_id), + ObligationCause::misc(self.span, self.id.owner.def_id), partial_eq_trait_id, 0, [ty, ty], diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index adf6ae4c727..9f006a76162 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -445,7 +445,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { _fd: &'tcx hir::FnDecl<'tcx>, b: hir::BodyId, _s: rustc_span::Span, - _id: HirId, + _id: LocalDefId, ) { if matches!(fk, intravisit::FnKind::Closure) { self.visit_body(self.tcx.hir().body(b)) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1468afc6456..9a617159813 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -540,7 +540,8 @@ fn fn_sig_and_body( // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + let (_, fn_body_id) = + hir::map::associated_body(hir_node).expect("HIR node is a function with body"); (hir_node.fn_sig(), tcx.hir().body(fn_body_id)) } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 39c61a34afc..a9fd95f4541 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -54,7 +54,8 @@ use crate::deref_separator::deref_finder; use crate::simplify; use crate::util::expand_aggregate; use crate::MirPass; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::GeneratorKind; @@ -70,6 +71,9 @@ use rustc_mir_dataflow::impls::{ }; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{self, Analysis}; +use rustc_span::def_id::DefId; +use rustc_span::symbol::sym; +use rustc_span::Span; use rustc_target::abi::VariantIdx; use rustc_target::spec::PanicStrategy; use std::{iter, ops}; @@ -854,7 +858,7 @@ fn sanitize_witness<'tcx>( body: &Body<'tcx>, witness: Ty<'tcx>, upvars: Vec<Ty<'tcx>>, - saved_locals: &GeneratorSavedLocals, + layout: &GeneratorLayout<'tcx>, ) { let did = body.source.def_id(); let param_env = tcx.param_env(did); @@ -873,31 +877,36 @@ fn sanitize_witness<'tcx>( } }; - for (local, decl) in body.local_decls.iter_enumerated() { - // Ignore locals which are internal or not saved between yields. - if !saved_locals.contains(local) || decl.internal { + let mut mismatches = Vec::new(); + for fty in &layout.field_tys { + if fty.ignore_for_traits { continue; } - let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); + let decl_ty = tcx.normalize_erasing_regions(param_env, fty.ty); // Sanity check that typeck knows about the type of locals which are // live across a suspension point if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { - span_bug!( - body.span, - "Broken MIR: generator contains type {} in MIR, \ - but typeck only knows about {} and {:?}", - decl_ty, - allowed, - allowed_upvars - ); + mismatches.push(decl_ty); } } + + if !mismatches.is_empty() { + span_bug!( + body.span, + "Broken MIR: generator contains type {:?} in MIR, \ + but typeck only knows about {} and {:?}", + mismatches, + allowed, + allowed_upvars + ); + } } fn compute_layout<'tcx>( + tcx: TyCtxt<'tcx>, liveness: LivenessInfo, - body: &mut Body<'tcx>, + body: &Body<'tcx>, ) -> ( FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>, GeneratorLayout<'tcx>, @@ -915,9 +924,33 @@ fn compute_layout<'tcx>( let mut locals = IndexVec::<GeneratorSavedLocal, _>::new(); let mut tys = IndexVec::<GeneratorSavedLocal, _>::new(); for (saved_local, local) in saved_locals.iter_enumerated() { - locals.push(local); - tys.push(body.local_decls[local].ty); debug!("generator saved local {:?} => {:?}", saved_local, local); + + locals.push(local); + let decl = &body.local_decls[local]; + debug!(?decl); + + let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir { + match decl.local_info { + // Do not include raw pointers created from accessing `static` items, as those could + // well be re-created by another access to the same static. + Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local, + // Fake borrows are only read by fake reads, so do not have any reality in + // post-analysis MIR. + Some(box LocalInfo::FakeBorrow) => true, + _ => false, + } + } else { + // FIXME(#105084) HIR-based drop tracking does not account for all the temporaries that + // MIR building may introduce. This leads to wrongly ignored types, but this is + // necessary for internal consistency and to avoid ICEs. + decl.internal + }; + let decl = + GeneratorSavedTy { ty: decl.ty, source_info: decl.source_info, ignore_for_traits }; + debug!(?decl); + + tys.push(decl); } // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states. @@ -947,7 +980,7 @@ fn compute_layout<'tcx>( // just use the first one here. That's fine; fields do not move // around inside generators, so it doesn't matter which variant // index we access them by. - remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx)); + remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); @@ -957,6 +990,7 @@ fn compute_layout<'tcx>( let layout = GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts }; + debug!(?layout); (remap, layout, storage_liveness) } @@ -1351,6 +1385,42 @@ fn create_cases<'tcx>( .collect() } +#[instrument(level = "debug", skip(tcx), ret)] +pub(crate) fn mir_generator_witnesses<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> GeneratorLayout<'tcx> { + assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); + let def_id = def_id.expect_local(); + + let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id)); + let body = body.borrow(); + let body = &*body; + + // The first argument is the generator type passed by value + let gen_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; + + // Get the interior types and substs which typeck computed + let movable = match *gen_ty.kind() { + ty::Generator(_, _, movability) => movability == hir::Movability::Movable, + _ => span_bug!(body.span, "unexpected generator type {}", gen_ty), + }; + + // When first entering the generator, move the resume argument into its new local. + let always_live_locals = always_storage_live_locals(&body); + + let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); + + // Extract locals which are live across suspension point into `layout` + // `remap` gives a mapping from local indices onto generator struct indices + // `storage_liveness` tells us which locals have live storage at suspension points + let (_, generator_layout, _) = compute_layout(tcx, liveness_info, body); + + check_suspend_tys(tcx, &generator_layout, &body); + + generator_layout +} + impl<'tcx> MirPass<'tcx> for StateTransform { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let Some(yield_ty) = body.yield_ty() else { @@ -1363,14 +1433,14 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // The first argument is the generator type passed by value let gen_ty = body.local_decls.raw[1].ty; - // Get the interior types and substs which typeck computed - let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { + // Get the discriminant type and substs which typeck computed + let (discr_ty, upvars, interior, movable) = match *gen_ty.kind() { ty::Generator(_, substs, movability) => { let substs = substs.as_generator(); ( - substs.upvar_tys().collect(), - substs.witness(), substs.discr_ty(tcx), + substs.upvar_tys().collect::<Vec<_>>(), + substs.witness(), movability == hir::Movability::Movable, ) } @@ -1434,8 +1504,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); - sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals); - if tcx.sess.opts.unstable_opts.validate_mir { let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias { assigned_local: None, @@ -1449,7 +1517,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // Extract locals which are live across suspension point into `layout` // `remap` gives a mapping from local indices onto generator struct indices // `storage_liveness` tells us which locals have live storage at suspension points - let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); + let (remap, layout, storage_liveness) = compute_layout(tcx, liveness_info, body); + + if tcx.sess.opts.unstable_opts.validate_mir + && !tcx.sess.opts.unstable_opts.drop_tracking_mir + { + sanitize_witness(tcx, body, interior, upvars, &layout); + } let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); @@ -1631,3 +1705,212 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { } } } + +fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &GeneratorLayout<'tcx>, body: &Body<'tcx>) { + let mut linted_tys = FxHashSet::default(); + + // We want a user-facing param-env. + let param_env = tcx.param_env(body.source.def_id()); + + for (variant, yield_source_info) in + layout.variant_fields.iter().zip(&layout.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &layout.field_tys[local]; + debug!(?decl); + + if !decl.ignore_for_traits && linted_tys.insert(decl.ty) { + let Some(hir_id) = decl.source_info.scope.lint_root(&body.source_scopes) else { continue }; + + check_must_not_suspend_ty( + tcx, + decl.ty, + hir_id, + param_env, + SuspendCheckData { + source_span: decl.source_info.span, + yield_span: yield_source_info.span, + plural_len: 1, + ..Default::default() + }, + ); + } + } + } +} + +#[derive(Default)] +struct SuspendCheckData<'a> { + source_span: Span, + yield_span: Span, + descr_pre: &'a str, + descr_post: &'a str, + plural_len: usize, +} + +// Returns whether it emitted a diagnostic or not +// Note that this fn and the proceeding one are based on the code +// for creating must_use diagnostics +// +// Note that this technique was chosen over things like a `Suspend` marker trait +// as it is simpler and has precedent in the compiler +fn check_must_not_suspend_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + hir_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + data: SuspendCheckData<'_>, +) -> bool { + if ty.is_unit() { + return false; + } + + let plural_suffix = pluralize!(data.plural_len); + + debug!("Checking must_not_suspend for {}", ty); + + match *ty.kind() { + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", data.descr_pre); + check_must_not_suspend_ty( + tcx, + boxed_ty, + hir_id, + param_env, + SuspendCheckData { descr_pre, ..data }, + ) + } + ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), + // FIXME: support adding the attribute to TAITs + ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { + let mut has_emitted = false; + for &(predicate, _) in tcx.explicit_item_bounds(def) { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = + predicate.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; + let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_pre, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _, _) => { + let mut has_emitted = false; + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + let def_id = trait_ref.def_id; + let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); + if check_must_not_suspend_def( + tcx, + def_id, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(fields) => { + let mut has_emitted = false; + for (i, ty) in fields.iter().enumerate() { + let descr_post = &format!(" in tuple element {i}"); + if check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => { + let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { + descr_pre, + plural_len: len.try_eval_usize(tcx, param_env).unwrap_or(0) as usize + 1, + ..data + }, + ) + } + // If drop tracking is enabled, we want to look through references, since the referrent + // may not be considered live across the await point. + ty::Ref(_region, ty, _mutability) => { + let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + tcx, + ty, + hir_id, + param_env, + SuspendCheckData { descr_pre, ..data }, + ) + } + _ => false, + } +} + +fn check_must_not_suspend_def( + tcx: TyCtxt<'_>, + def_id: DefId, + hir_id: hir::HirId, + data: SuspendCheckData<'_>, +) -> bool { + if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) { + let msg = format!( + "{}`{}`{} held across a suspend point, but should not be", + data.descr_pre, + tcx.def_path_str(def_id), + data.descr_post, + ); + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + msg, + |lint| { + // add span pointing to the offending yield/await + lint.span_label(data.yield_span, "the value is held across this suspend point"); + + // Add optional reason note + if let Some(note) = attr.value_str() { + // FIXME(guswynn): consider formatting this better + lint.span_note(data.source_span, note.as_str()); + } + + // Add some quick suggestions on what to do + // FIXME: can `drop` work as a suggestion here as well? + lint.span_help( + data.source_span, + "consider using a block (`{ ... }`) \ + to shrink the value's scope, ending before the suspend point", + ) + }, + ); + + true + } else { + false + } +} diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 69627fc5cb2..84640b703c8 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -947,12 +947,12 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { return; }; - let Some(&f_ty) = layout.field_tys.get(local) else { + let Some(f_ty) = layout.field_tys.get(local) else { self.validation = Err("malformed MIR"); return; }; - f_ty + f_ty.ty } else { let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else { self.validation = Err("malformed MIR"); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4a598862d10..fcb09fa02dd 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -123,6 +123,7 @@ pub fn provide(providers: &mut Providers) { mir_drops_elaborated_and_const_checked, mir_for_ctfe, mir_for_ctfe_of_const_arg, + mir_generator_witnesses: generator::mir_generator_witnesses, optimized_mir, is_mir_available, is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did), @@ -425,6 +426,9 @@ fn mir_drops_elaborated_and_const_checked( return tcx.mir_drops_elaborated_and_const_checked(def); } + if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir { + tcx.ensure().mir_generator_witnesses(def.did); + } let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def); let is_fn_like = tcx.def_kind(def.did).is_fn_like(); diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs new file mode 100644 index 00000000000..386bf026bb4 --- /dev/null +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -0,0 +1,119 @@ +use super::UnmatchedBrace; +use rustc_ast::token::Delimiter; +use rustc_errors::Diagnostic; +use rustc_span::source_map::SourceMap; +use rustc_span::Span; + +#[derive(Default)] +pub struct TokenTreeDiagInfo { + /// Stack of open delimiters and their spans. Used for error message. + pub open_braces: Vec<(Delimiter, Span)>, + pub unmatched_braces: Vec<UnmatchedBrace>, + + /// Used only for error recovery when arriving to EOF with mismatched braces. + pub last_unclosed_found_span: Option<Span>, + + /// Collect empty block spans that might have been auto-inserted by editors. + pub empty_block_spans: Vec<Span>, + + /// Collect the spans of braces (Open, Close). Used only + /// for detecting if blocks are empty and only braces. + pub matching_block_spans: Vec<(Span, Span)>, +} + +pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { + match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { + (Some(open_padding), Some(close_padding)) => open_padding == close_padding, + _ => false, + } +} + +// When we get a `)` or `]` for `{`, we should emit help message here +// it's more friendly compared to report `unmatched error` in later phase +pub fn report_missing_open_delim( + err: &mut Diagnostic, + unmatched_braces: &[UnmatchedBrace], +) -> bool { + let mut reported_missing_open = false; + for unmatch_brace in unmatched_braces.iter() { + if let Some(delim) = unmatch_brace.found_delim + && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) + { + let missed_open = match delim { + Delimiter::Parenthesis => "(", + Delimiter::Bracket => "[", + _ => unreachable!(), + }; + err.span_label( + unmatch_brace.found_span.shrink_to_lo(), + format!("missing open `{}` for this delimiter", missed_open), + ); + reported_missing_open = true; + } + } + reported_missing_open +} + +pub fn report_suspicious_mismatch_block( + err: &mut Diagnostic, + diag_info: &TokenTreeDiagInfo, + sm: &SourceMap, + delim: Delimiter, +) { + if report_missing_open_delim(err, &diag_info.unmatched_braces) { + return; + } + + let mut matched_spans: Vec<(Span, bool)> = diag_info + .matching_block_spans + .iter() + .map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close))) + .collect(); + + // sort by `lo`, so the large block spans in the front + matched_spans.sort_by(|a, b| a.0.lo().cmp(&b.0.lo())); + + // We use larger block whose identation is well to cover those inner mismatched blocks + // O(N^2) here, but we are on error reporting path, so it is fine + for i in 0..matched_spans.len() { + let (block_span, same_ident) = matched_spans[i]; + if same_ident { + for j in i + 1..matched_spans.len() { + let (inner_block, inner_same_ident) = matched_spans[j]; + if block_span.contains(inner_block) && !inner_same_ident { + matched_spans[j] = (inner_block, true); + } + } + } + } + + // Find the inner-most span candidate for final report + let candidate_span = + matched_spans.into_iter().rev().find(|&(_, same_ident)| !same_ident).map(|(span, _)| span); + + if let Some(block_span) = candidate_span { + err.span_label(block_span.shrink_to_lo(), "this delimiter might not be properly closed..."); + err.span_label( + block_span.shrink_to_hi(), + "...as it matches this but it has different indentation", + ); + + // If there is a empty block in the mismatched span, note it + if delim == Delimiter::Brace { + for span in diag_info.empty_block_spans.iter() { + if block_span.contains(*span) { + err.span_label(*span, "block is empty, you might have not meant to close it"); + break; + } + } + } + } else { + // If there is no suspicious span, give the last properly closed block may help + if let Some(parent) = diag_info.matching_block_spans.last() + && diag_info.open_braces.last().is_none() + && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) { + err.span_label(parent.0, "this opening brace..."); + err.span_label(parent.1, "...matches this closing brace"); + } + } +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 9fe8d9836ba..e957224a033 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -17,6 +17,7 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{edition::Edition, BytePos, Pos, Span}; +mod diagnostics; mod tokentrees; mod unescape_error_reporting; mod unicode_chars; diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index b2701817d48..0de8f79112c 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,29 +1,18 @@ +use super::diagnostics::report_suspicious_mismatch_block; +use super::diagnostics::same_identation_level; +use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedBrace}; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::{PErr, PResult}; -use rustc_span::Span; pub(super) struct TokenTreesReader<'a> { string_reader: StringReader<'a>, /// The "next" token, which has been obtained from the `StringReader` but /// not yet handled by the `TokenTreesReader`. token: Token, - /// Stack of open delimiters and their spans. Used for error message. - open_braces: Vec<(Delimiter, Span)>, - unmatched_braces: Vec<UnmatchedBrace>, - /// The type and spans for all braces - /// - /// Used only for error recovery when arriving to EOF with mismatched braces. - matching_delim_spans: Vec<(Delimiter, Span, Span)>, - last_unclosed_found_span: Option<Span>, - /// Collect empty block spans that might have been auto-inserted by editors. - last_delim_empty_block_spans: FxHashMap<Delimiter, Span>, - /// Collect the spans of braces (Open, Close). Used only - /// for detecting if blocks are empty and only braces. - matching_block_spans: Vec<(Span, Span)>, + diag_info: TokenTreeDiagInfo, } impl<'a> TokenTreesReader<'a> { @@ -33,15 +22,10 @@ impl<'a> TokenTreesReader<'a> { let mut tt_reader = TokenTreesReader { string_reader, token: Token::dummy(), - open_braces: Vec::new(), - unmatched_braces: Vec::new(), - matching_delim_spans: Vec::new(), - last_unclosed_found_span: None, - last_delim_empty_block_spans: FxHashMap::default(), - matching_block_spans: Vec::new(), + diag_info: TokenTreeDiagInfo::default(), }; let res = tt_reader.parse_token_trees(/* is_delimited */ false); - (res, tt_reader.unmatched_braces) + (res, tt_reader.diag_info.unmatched_braces) } // Parse a stream of tokens into a list of `TokenTree`s. @@ -92,9 +76,9 @@ impl<'a> TokenTreesReader<'a> { fn eof_err(&mut self) -> PErr<'a> { let msg = "this file contains an unclosed delimiter"; let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg); - for &(_, sp) in &self.open_braces { + for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); - self.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_braces.push(UnmatchedBrace { expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, @@ -103,23 +87,13 @@ impl<'a> TokenTreesReader<'a> { }); } - if let Some((delim, _)) = self.open_braces.last() { - if let Some((_, open_sp, close_sp)) = - self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| { - let sm = self.string_reader.sess.source_map(); - if let Some(close_padding) = sm.span_to_margin(*close_sp) { - if let Some(open_padding) = sm.span_to_margin(*open_sp) { - return delim == d && close_padding != open_padding; - } - } - false - }) - // these are in reverse order as they get inserted on close, but - { - // we want the last open/first close - err.span_label(*open_sp, "this delimiter might not be properly closed..."); - err.span_label(*close_sp, "...as it matches this but it has different indentation"); - } + if let Some((delim, _)) = self.diag_info.open_braces.last() { + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + &self.string_reader.sess.source_map(), + *delim, + ) } err } @@ -128,7 +102,7 @@ impl<'a> TokenTreesReader<'a> { // The span for beginning of the delimited section let pre_span = self.token.span; - self.open_braces.push((open_delim, self.token.span)); + self.diag_info.open_braces.push((open_delim, self.token.span)); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -137,35 +111,29 @@ impl<'a> TokenTreesReader<'a> { // Expand to cover the entire delimited token tree let delim_span = DelimSpan::from_pair(pre_span, self.token.span); + let sm = self.string_reader.sess.source_map(); match self.token.kind { // Correct delimiter. token::CloseDelim(close_delim) if close_delim == open_delim => { - let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap(); let close_brace_span = self.token.span; - if tts.is_empty() { + if tts.is_empty() && close_delim == Delimiter::Brace { let empty_block_span = open_brace_span.to(close_brace_span); - let sm = self.string_reader.sess.source_map(); if !sm.is_multiline(empty_block_span) { // Only track if the block is in the form of `{}`, otherwise it is // likely that it was written on purpose. - self.last_delim_empty_block_spans.insert(open_delim, empty_block_span); + self.diag_info.empty_block_spans.push(empty_block_span); } } - //only add braces + // only add braces if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) { - self.matching_block_spans.push((open_brace_span, close_brace_span)); + // Add all the matching spans, we will sort by span later + self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span)); } - if self.open_braces.is_empty() { - // Clear up these spans to avoid suggesting them as we've found - // properly matched delimiters so far for an entire block. - self.matching_delim_spans.clear(); - } else { - self.matching_delim_spans.push((open_brace, open_brace_span, close_brace_span)); - } // Move past the closing delimiter. self.token = self.string_reader.next_token().0; } @@ -174,28 +142,25 @@ impl<'a> TokenTreesReader<'a> { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.token.span) { + if self.diag_info.last_unclosed_found_span != Some(self.token.span) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.token.span); + self.diag_info.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. - if let Some(&(_, sp)) = self.open_braces.last() { + if let Some(&(_, sp)) = self.diag_info.open_braces.last() { unclosed_delimiter = Some(sp); }; - let sm = self.string_reader.sess.source_map(); - if let Some(current_padding) = sm.span_to_margin(self.token.span) { - for (brace, brace_span) in &self.open_braces { - if let Some(padding) = sm.span_to_margin(*brace_span) { - // high likelihood of these two corresponding - if current_padding == padding && brace == &close_delim { - candidate = Some(*brace_span); - } - } + for (brace, brace_span) in &self.diag_info.open_braces { + if same_identation_level(&sm, self.token.span, *brace_span) + && brace == &close_delim + { + // high likelihood of these two corresponding + candidate = Some(*brace_span); } } - let (tok, _) = self.open_braces.pop().unwrap(); - self.unmatched_braces.push(UnmatchedBrace { + let (tok, _) = self.diag_info.open_braces.pop().unwrap(); + self.diag_info.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, @@ -203,7 +168,7 @@ impl<'a> TokenTreesReader<'a> { candidate_span: candidate, }); } else { - self.open_braces.pop(); + self.diag_info.open_braces.pop(); } // If the incorrect delimiter matches an earlier opening @@ -213,7 +178,7 @@ impl<'a> TokenTreesReader<'a> { // fn foo() { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` - if !self.open_braces.iter().any(|&(b, _)| b == close_delim) { + if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) { self.token = self.string_reader.next_token().0; } } @@ -236,22 +201,12 @@ impl<'a> TokenTreesReader<'a> { let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg); - // Braces are added at the end, so the last element is the biggest block - if let Some(parent) = self.matching_block_spans.last() { - if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { - // Check if the (empty block) is in the last properly closed block - if (parent.0.to(parent.1)).contains(span) { - err.span_label(span, "block is empty, you might have not meant to close it"); - } else { - err.span_label(parent.0, "this opening brace..."); - err.span_label(parent.1, "...matches this closing brace"); - } - } else { - err.span_label(parent.0, "this opening brace..."); - err.span_label(parent.1, "...matches this closing brace"); - } - } - + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + &self.string_reader.sess.source_map(), + delim, + ); err.span_label(self.token.span, "unexpected closing delimiter"); err } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index eda7046c748..f4c08031bcc 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2353,6 +2353,28 @@ impl<'a> Parser<'a> { Err(err) } + /// Try to recover from an unbraced const argument whose first token [could begin a type][ty]. + /// + /// [ty]: token::Token::can_begin_type + pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty( + &mut self, + mut snapshot: SnapshotParser<'a>, + ) -> Option<P<ast::Expr>> { + match snapshot.parse_expr_res(Restrictions::CONST_EXPR, None) { + // Since we don't know the exact reason why we failed to parse the type or the + // expression, employ a simple heuristic to weed out some pathological cases. + Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => { + self.restore_snapshot(snapshot); + Some(expr) + } + Ok(_) => None, + Err(err) => { + err.cancel(); + None + } + } + } + /// Creates a dummy const argument, and reports that the expression must be enclosed in braces pub fn dummy_const_arg_needs_braces( &self, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 5333d3b8587..2e706a00cf7 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -675,22 +675,42 @@ impl<'a> Parser<'a> { GenericArg::Const(self.parse_const_arg()?) } else if self.check_type() { // Parse type argument. - let is_const_fn = - self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)); - let mut snapshot = self.create_snapshot_for_diagnostic(); + + // Proactively create a parser snapshot enabling us to rewind and try to reparse the + // input as a const expression in case we fail to parse a type. If we successfully + // do so, we will report an error that it needs to be wrapped in braces. + let mut snapshot = None; + if self.may_recover() && self.token.can_begin_expr() { + snapshot = Some(self.create_snapshot_for_diagnostic()); + } + match self.parse_ty() { - Ok(ty) => GenericArg::Type(ty), + Ok(ty) => { + // Since the type parser recovers from some malformed slice and array types and + // successfully returns a type, we need to look for `TyKind::Err`s in the + // type to determine if error recovery has occurred and if the input is not a + // syntactically valid type after all. + if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind + && let ast::TyKind::Err = inner_ty.kind + && let Some(snapshot) = snapshot + && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + { + return Ok(Some(self.dummy_const_arg_needs_braces( + self.struct_span_err(expr.span, "invalid const generic expression"), + expr.span, + ))); + } + + GenericArg::Type(ty) + } Err(err) => { - if is_const_fn { - match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) { - Ok(expr) => { - self.restore_snapshot(snapshot); - return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); - } - Err(err) => { - err.cancel(); - } - } + if let Some(snapshot) = snapshot + && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + { + return Ok(Some(self.dummy_const_arg_needs_braces( + err, + expr.span, + ))); } // Try to recover from possible `const` arg without braces. return self.recover_const_arg(start, err).map(Some); diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 7b016cadac3..a6dfcd29762 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -16,7 +16,6 @@ pub use Alignment::*; pub use Count::*; -pub use Flag::*; pub use Piece::*; pub use Position::*; @@ -111,8 +110,14 @@ pub struct FormatSpec<'a> { pub fill: Option<char>, /// Optionally specified alignment. pub align: Alignment, - /// Packed version of various flags provided. - pub flags: u32, + /// The `+` or `-` flag. + pub sign: Option<Sign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. + pub zero_pad: bool, + /// The `x` or `X` flag. (Only for `Debug`.) + pub debug_hex: Option<DebugHex>, /// The integer precision to use. pub precision: Count<'a>, /// The span of the precision formatting flag (for diagnostics). @@ -162,24 +167,22 @@ pub enum Alignment { AlignUnknown, } -/// Various flags which can be applied to format strings. The meaning of these -/// flags is defined by the formatters themselves. +/// Enum for the sign flags. #[derive(Copy, Clone, Debug, PartialEq)] -pub enum Flag { - /// A `+` will be used to denote positive numbers. - FlagSignPlus, - /// A `-` will be used to denote negative numbers. This is the default. - FlagSignMinus, - /// An alternate form will be used for the value. In the case of numbers, - /// this means that the number will be prefixed with the supplied string. - FlagAlternate, - /// For numbers, this means that the number will be padded with zeroes, - /// and the sign (`+` or `-`) will precede them. - FlagSignAwareZeroPad, - /// For Debug / `?`, format integers in lower-case hexadecimal. - FlagDebugLowerHex, - /// For Debug / `?`, format integers in upper-case hexadecimal. - FlagDebugUpperHex, +pub enum Sign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +/// Enum for the debug hex flags. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum DebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, } /// A count is used for the precision and width parameters of an integer, and @@ -597,7 +600,10 @@ impl<'a> Parser<'a> { let mut spec = FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountImplied, @@ -626,13 +632,13 @@ impl<'a> Parser<'a> { } // Sign flags if self.consume('+') { - spec.flags |= 1 << (FlagSignPlus as u32); + spec.sign = Some(Sign::Plus); } else if self.consume('-') { - spec.flags |= 1 << (FlagSignMinus as u32); + spec.sign = Some(Sign::Minus); } // Alternate marker if self.consume('#') { - spec.flags |= 1 << (FlagAlternate as u32); + spec.alternate = true; } // Width and precision let mut havewidth = false; @@ -647,7 +653,7 @@ impl<'a> Parser<'a> { spec.width_span = Some(self.span(end - 1, end + 1)); havewidth = true; } else { - spec.flags |= 1 << (FlagSignAwareZeroPad as u32); + spec.zero_pad = true; } } @@ -678,14 +684,14 @@ impl<'a> Parser<'a> { // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { - spec.flags |= 1 << (FlagDebugLowerHex as u32); + spec.debug_hex = Some(DebugHex::Lower); spec.ty = "?"; } else { spec.ty = "x"; } } else if self.consume('X') { if self.consume('?') { - spec.flags |= 1 << (FlagDebugUpperHex as u32); + spec.debug_hex = Some(DebugHex::Upper); spec.ty = "?"; } else { spec.ty = "X"; @@ -708,7 +714,10 @@ impl<'a> Parser<'a> { let mut spec = FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountImplied, diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 2992ba845ab..45314e2fb55 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -10,7 +10,10 @@ fn fmtdflt() -> FormatSpec<'static> { return FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -126,7 +129,10 @@ fn format_type() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -147,7 +153,10 @@ fn format_align_fill() { format: FormatSpec { fill: None, align: AlignRight, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -165,7 +174,10 @@ fn format_align_fill() { format: FormatSpec { fill: Some('0'), align: AlignLeft, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -183,7 +195,10 @@ fn format_align_fill() { format: FormatSpec { fill: Some('*'), align: AlignLeft, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -204,7 +219,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, precision_span: None, width: CountIs(10), @@ -222,7 +240,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(10), precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(10), @@ -240,7 +261,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(10), precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(0), @@ -258,7 +282,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsStar(0), precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, @@ -276,7 +303,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsParam(10), width: CountImplied, precision_span: Some(InnerSpan::new(3, 7)), @@ -294,7 +324,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIsName("b", InnerSpan { start: 6, end: 7 }), precision_span: Some(InnerSpan { start: 5, end: 8 }), width: CountIsName("a", InnerSpan { start: 3, end: 4 }), @@ -312,7 +345,10 @@ fn format_counts() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountIs(4), precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, @@ -333,7 +369,10 @@ fn format_flags() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: (1 << FlagSignMinus as u32), + sign: Some(Sign::Minus), + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -351,7 +390,10 @@ fn format_flags() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32), + sign: Some(Sign::Plus), + alternate: true, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, @@ -374,7 +416,10 @@ fn format_mixture() { format: FormatSpec { fill: None, align: AlignUnknown, - flags: 0, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, precision: CountImplied, width: CountImplied, precision_span: None, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f4673c332b8..25cc65ba04c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -453,7 +453,9 @@ impl CheckAttrVisitor<'_> { /// Debugging aid for `object_lifetime_default` query. fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; - if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { + if let Some(owner_id) = hir_id.as_owner() + && let Some(generics) = tcx.hir().get_generics(owner_id.def_id) + { for p in generics.params { let hir::GenericParamKind::Type { .. } = p.kind else { continue }; let default = tcx.object_lifetime_default(p.def_id); @@ -1943,7 +1945,7 @@ impl CheckAttrVisitor<'_> { ) -> bool { match target { Target::Fn | Target::Method(_) - if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id).to_def_id()) => + if self.tcx.is_const_fn_raw(hir_id.expect_owner().to_def_id()) => { true } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 94171b4b0c8..127acb46e92 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -451,29 +451,23 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { // referenced by it should be considered as used. let in_pat = mem::replace(&mut self.in_pat, false); - self.live_symbols.insert(self.tcx.hir().local_def_id(c.hir_id)); + self.live_symbols.insert(c.def_id); intravisit::walk_anon_const(self, c); self.in_pat = in_pat; } } -fn has_allow_dead_code_or_lang_attr_helper( - tcx: TyCtxt<'_>, - id: hir::HirId, - lint: &'static lint::Lint, -) -> bool { - let attrs = tcx.hir().attrs(id); - if tcx.sess.contains_name(attrs, sym::lang) { +fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + if tcx.has_attr(def_id.to_def_id(), sym::lang) { return true; } // Stable attribute for #[lang = "panic_impl"] - if tcx.sess.contains_name(attrs, sym::panic_handler) { + if tcx.has_attr(def_id.to_def_id(), sym::panic_handler) { return true; } - let def_id = tcx.hir().local_def_id(id); if tcx.def_kind(def_id).has_codegen_attrs() { let cg_attrs = tcx.codegen_fn_attrs(def_id); @@ -487,11 +481,8 @@ fn has_allow_dead_code_or_lang_attr_helper( } } - tcx.lint_level_at_node(lint, id).0 == lint::Allow -} - -fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { - has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE) + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow } // These check_* functions seeds items that @@ -513,7 +504,7 @@ fn check_item<'tcx>( struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>, id: hir::ItemId, ) { - let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id()); + let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id); if allow_dead_code { worklist.push(id.owner_id.def_id); } @@ -548,9 +539,7 @@ fn check_item<'tcx>( // And we access the Map here to get HirId from LocalDefId for id in local_def_ids { - if of_trait.is_some() - || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id)) - { + if of_trait.is_some() || has_allow_dead_code_or_lang_attr(tcx, id) { worklist.push(id); } } @@ -558,9 +547,9 @@ fn check_item<'tcx>( DefKind::Struct => { let item = tcx.hir().item(id); if let hir::ItemKind::Struct(ref variant_data, _) = item.kind - && let Some(ctor_hir_id) = variant_data.ctor_hir_id() + && let Some(ctor_def_id) = variant_data.ctor_def_id() { - struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id); + struct_constructors.insert(ctor_def_id, item.owner_id.def_id); } } DefKind::GlobalAsm => { @@ -576,7 +565,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) - && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id()) + && has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { worklist.push(trait_item.owner_id.def_id); } @@ -585,7 +574,7 @@ fn check_trait_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::Tr fn check_foreign_item(tcx: TyCtxt<'_>, worklist: &mut Vec<LocalDefId>, id: hir::ForeignItemId) { if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn) - && has_allow_dead_code_or_lang_attr(tcx, id.hir_id()) + && has_allow_dead_code_or_lang_attr(tcx, id.owner_id.def_id) { worklist.push(id.owner_id.def_id); } @@ -806,8 +795,7 @@ impl<'tcx> DeadVisitor<'tcx> { if self.live_symbols.contains(&def_id) { return; } - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - if has_allow_dead_code_or_lang_attr(self.tcx, hir_id) { + if has_allow_dead_code_or_lang_attr(self.tcx, def_id) { return; } let Some(name) = self.tcx.opt_item_name(def_id.to_def_id()) else { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d1b896e940e..51a19c8e3c0 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -12,6 +12,7 @@ use rustc_hir::HirId; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; use rustc_middle::util::common::to_readable_str; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -363,7 +364,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fd: &'v hir::FnDecl<'v>, b: hir::BodyId, _: Span, - id: hir::HirId, + id: LocalDefId, ) { self.record("FnDecl", Id::None, fd); hir_visit::walk_fn(self, fk, fd, b, id) diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9a40b847d85..fdd0e5dab70 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -15,9 +15,9 @@ use crate::weak_lang_items; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::{extract, GenericRequirement}; -use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_hir::{LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; use rustc_span::{symbol::kw::Empty, Span}; @@ -40,13 +40,13 @@ impl<'tcx> LanguageItemCollector<'tcx> { LanguageItemCollector { tcx, items: LanguageItems::new() } } - fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { - let attrs = self.tcx.hir().attrs(hir_id); + fn check_for_lang(&mut self, actual_target: Target, def_id: LocalDefId) { + let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); if let Some((name, span)) = extract(&attrs) { match LangItem::from_name(name) { // Known lang item with attribute on correct target. Some(lang_item) if actual_target == lang_item.target() => { - self.collect_item_extended(lang_item, hir_id, span); + self.collect_item_extended(lang_item, def_id, span); } // Known lang item with attribute on incorrect target. Some(lang_item) => { @@ -142,8 +142,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Like collect_item() above, but also checks whether the lang item is declared // with the right number of generic arguments. - fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) { - let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); + fn collect_item_extended(&mut self, lang_item: LangItem, item_def_id: LocalDefId, span: Span) { let name = lang_item.name(); // Now check whether the lang_item has the expected number of generic @@ -154,7 +153,8 @@ impl<'tcx> LanguageItemCollector<'tcx> { // Some other types like Box and various functions like drop_in_place // have minimum requirements. - if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id) + if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = + self.tcx.hir().get_by_def_id(item_def_id) { let (actual_num, generics_span) = match kind.generics() { Some(generics) => (generics.params.len(), generics.span), @@ -191,7 +191,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } } - self.collect_item(lang_item, item_def_id); + self.collect_item(lang_item, item_def_id.to_def_id()); } } @@ -211,13 +211,14 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let crate_items = tcx.hir_crate_items(()); for id in crate_items.items() { - collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id()); + collector + .check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.owner_id.def_id); if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) { let item = tcx.hir().item(id); if let hir::ItemKind::Enum(def, ..) = &item.kind { for variant in def.variants { - collector.check_for_lang(Target::Variant, variant.hir_id); + collector.check_for_lang(Target::Variant, variant.def_id); } } } @@ -226,13 +227,13 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { // FIXME: avoid calling trait_item() when possible for id in crate_items.trait_items() { let item = tcx.hir().trait_item(id); - collector.check_for_lang(Target::from_trait_item(item), item.hir_id()) + collector.check_for_lang(Target::from_trait_item(item), item.owner_id.def_id) } // FIXME: avoid calling impl_item() when possible for id in crate_items.impl_items() { let item = tcx.hir().impl_item(id); - collector.check_for_lang(target_from_impl_item(tcx, item), item.hir_id()) + collector.check_for_lang(target_from_impl_item(tcx, item), item.owner_id.def_id) } // Extract out the found lang items. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 34e1abb78b2..0bde7502e39 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -855,7 +855,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { /// See issue #94972 for details on why this is a special case fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // Get the LocalDefId so we can lookup the item to check the kind. - let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; }; + let Some(owner) = id.as_owner() else { return false; }; + let def_id = owner.def_id; let Some(stab) = tcx.stability().local_stability(def_id) else { return false; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e969bb6db9e..43552861532 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; @@ -271,7 +271,8 @@ where | ty::FnPtr(..) | ty::Param(..) | ty::Error(_) - | ty::GeneratorWitness(..) => {} + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => {} ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } @@ -1878,7 +1879,7 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { struct PrivateItemsInPublicInterfacesChecker<'tcx> { tcx: TyCtxt<'tcx>, - old_error_set_ancestry: LocalDefIdSet, + old_error_set_ancestry: HirIdSet, } impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { @@ -1891,7 +1892,9 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { tcx: self.tcx, item_def_id: def_id, required_visibility, - has_old_errors: self.old_error_set_ancestry.contains(&def_id), + has_old_errors: self + .old_error_set_ancestry + .contains(&self.tcx.hir().local_def_id_to_hir_id(def_id)), in_assoc_ty: false, } } @@ -2157,15 +2160,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { } // Check for private types and traits in public interfaces. - let mut checker = PrivateItemsInPublicInterfacesChecker { - tcx, - // Only definition IDs are ever searched in `old_error_set_ancestry`, - // so we can filter away all non-definition IDs at this point. - old_error_set_ancestry: old_error_set_ancestry - .into_iter() - .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) - .collect(), - }; + let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, old_error_set_ancestry }; for id in tcx.hir().items() { checker.check_item(id); diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index a5f09de1c40..3982111e38e 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -211,7 +211,7 @@ impl<'tcx> DumpVisitor<'tcx> { None => continue, }; if !self.span.filter_generated(ident.span) { - let id = id_from_hir_id(hir_id, &self.save_ctxt); + let id = id_from_hir_id(hir_id); let span = self.span_from_span(ident.span); self.dumper.dump_def( @@ -240,17 +240,17 @@ impl<'tcx> DumpVisitor<'tcx> { &mut self, sig: &'tcx hir::FnSig<'tcx>, body: Option<hir::BodyId>, - def_id: LocalDefId, + owner_id: hir::OwnerId, ident: Ident, generics: &'tcx hir::Generics<'tcx>, span: Span, ) { - debug!("process_method: {:?}:{}", def_id, ident); + debug!("process_method: {:?}:{}", owner_id, ident); let map = self.tcx.hir(); - let hir_id = map.local_def_id_to_hir_id(def_id); - self.nest_typeck_results(def_id, |v| { - if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) { + let hir_id: hir::HirId = owner_id.into(); + self.nest_typeck_results(owner_id.def_id, |v| { + if let Some(mut method_data) = v.save_ctxt.get_method_data(owner_id, ident, span) { if let Some(body) = body { v.process_formals(map.body(body).params, &method_data.qualname); } @@ -258,9 +258,10 @@ impl<'tcx> DumpVisitor<'tcx> { method_data.value = fn_to_string(sig.decl, sig.header, Some(ident.name), generics, &[], None); - method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt); + method_data.sig = + sig::method_signature(owner_id, ident, generics, sig, &v.save_ctxt); - v.dumper.dump_def(&access_from!(v.save_ctxt, def_id), method_data); + v.dumper.dump_def(&access_from!(v.save_ctxt, owner_id.def_id), method_data); } // walk arg and return types @@ -282,14 +283,11 @@ impl<'tcx> DumpVisitor<'tcx> { fn process_struct_field_def( &mut self, field: &'tcx hir::FieldDef<'tcx>, - parent_id: hir::HirId, + parent_id: LocalDefId, ) { let field_data = self.save_ctxt.get_field_data(field, parent_id); if let Some(field_data) = field_data { - self.dumper.dump_def( - &access_from!(self.save_ctxt, self.tcx.hir().local_def_id(field.hir_id)), - field_data, - ); + self.dumper.dump_def(&access_from!(self.save_ctxt, field.def_id), field_data); } } @@ -309,7 +307,7 @@ impl<'tcx> DumpVisitor<'tcx> { // Append $id to name to make sure each one is unique. let qualname = format!("{}::{}${}", prefix, name, id); if !self.span.filter_generated(param_ss) { - let id = id_from_hir_id(param.hir_id, &self.save_ctxt); + let id = id_from_def_id(param.def_id.to_def_id()); let span = self.span_from_span(param_ss); self.dumper.dump_def( @@ -387,25 +385,24 @@ impl<'tcx> DumpVisitor<'tcx> { fn process_assoc_const( &mut self, - def_id: LocalDefId, + owner_id: hir::OwnerId, ident: Ident, typ: &'tcx hir::Ty<'tcx>, expr: Option<&'tcx hir::Expr<'tcx>>, parent_id: DefId, attrs: &'tcx [ast::Attribute], ) { - let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(owner_id.to_def_id())); if !self.span.filter_generated(ident.span) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt); + let sig = sig::assoc_const_signature(owner_id, ident.name, typ, expr, &self.save_ctxt); let span = self.span_from_span(ident.span); self.dumper.dump_def( - &access_from!(self.save_ctxt, def_id), + &access_from!(self.save_ctxt, owner_id.def_id), Def { kind: DefKind::Const, - id: id_from_hir_id(hir_id, &self.save_ctxt), + id: id_from_def_id(owner_id.to_def_id()), span, name: ident.name.to_string(), qualname, @@ -421,7 +418,7 @@ impl<'tcx> DumpVisitor<'tcx> { } // walk type and init value - self.nest_typeck_results(def_id, |v| { + self.nest_typeck_results(owner_id.def_id, |v| { v.visit_ty(typ); if let Some(expr) = expr { v.visit_expr(expr); @@ -456,8 +453,7 @@ impl<'tcx> DumpVisitor<'tcx> { if include_priv_fields { return Some(f.ident.to_string()); } - let def_id = self.save_ctxt.tcx.hir().local_def_id(f.hir_id); - if self.save_ctxt.tcx.visibility(def_id).is_public() { + if self.save_ctxt.tcx.visibility(f.def_id).is_public() { Some(f.ident.to_string()) } else { None @@ -466,7 +462,7 @@ impl<'tcx> DumpVisitor<'tcx> { .collect::<Vec<_>>() .join(", "); let value = format!("{} {{ {} }}", name, fields_str); - (value, fields.iter().map(|f| id_from_hir_id(f.hir_id, &self.save_ctxt)).collect()) + (value, fields.iter().map(|f| id_from_def_id(f.def_id.to_def_id())).collect()) } _ => (String::new(), vec![]), }; @@ -495,7 +491,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.nest_typeck_results(item.owner_id.def_id, |v| { for field in def.fields() { - v.process_struct_field_def(field, item.hir_id()); + v.process_struct_field_def(field, item.owner_id.def_id); v.visit_ty(&field.ty); } @@ -529,7 +525,7 @@ impl<'tcx> DumpVisitor<'tcx> { let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_hir_id(variant.hir_id, &self.save_ctxt); + let id = id_from_def_id(variant.def_id.to_def_id()); let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.hir_id); @@ -567,7 +563,7 @@ impl<'tcx> DumpVisitor<'tcx> { } if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_hir_id(variant.hir_id, &self.save_ctxt); + let id = id_from_def_id(variant.def_id.to_def_id()); let parent = Some(id_from_def_id(item.owner_id.to_def_id())); let attrs = self.tcx.hir().attrs(variant.hir_id); @@ -593,7 +589,7 @@ impl<'tcx> DumpVisitor<'tcx> { } for field in variant.data.fields() { - self.process_struct_field_def(field, variant.hir_id); + self.process_struct_field_def(field, variant.def_id); self.visit_ty(field.ty); } } @@ -883,7 +879,7 @@ impl<'tcx> DumpVisitor<'tcx> { // Rust uses the id of the pattern for var lookups, so we'll use it too. if !self.span.filter_generated(ident.span) { let qualname = format!("{}${}", ident, hir_id); - let id = id_from_hir_id(hir_id, &self.save_ctxt); + let id = id_from_hir_id(hir_id); let span = self.span_from_span(ident.span); self.dumper.dump_def( @@ -983,7 +979,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = body.map(|b| self.tcx.hir().body(b).value); let attrs = self.tcx.hir().attrs(trait_item.hir_id()); self.process_assoc_const( - trait_item.owner_id.def_id, + trait_item.owner_id, trait_item.ident, &ty, body, @@ -997,7 +993,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, body, - trait_item.owner_id.def_id, + trait_item.owner_id, trait_item.ident, &trait_item.generics, trait_item.span, @@ -1028,7 +1024,7 @@ impl<'tcx> DumpVisitor<'tcx> { decl_id: None, docs: self.save_ctxt.docs_for_attrs(attrs), sig: sig::assoc_type_signature( - trait_item.hir_id(), + trait_item.owner_id, trait_item.ident, Some(bounds), default_ty.as_deref(), @@ -1053,7 +1049,7 @@ impl<'tcx> DumpVisitor<'tcx> { let body = self.tcx.hir().body(body); let attrs = self.tcx.hir().attrs(impl_item.hir_id()); self.process_assoc_const( - impl_item.owner_id.def_id, + impl_item.owner_id, impl_item.ident, &ty, Some(&body.value), @@ -1065,7 +1061,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.process_method( sig, Some(body), - impl_item.owner_id.def_id, + impl_item.owner_id, impl_item.ident, &impl_item.generics, impl_item.span, @@ -1081,18 +1077,16 @@ impl<'tcx> DumpVisitor<'tcx> { } pub(crate) fn process_crate(&mut self) { - let id = hir::CRATE_HIR_ID; - let qualname = - format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id())); + let qualname = format!("::{}", self.tcx.def_path_str(CRATE_DEF_ID.to_def_id())); let sm = self.tcx.sess.source_map(); let krate_mod = self.tcx.hir().root_module(); let filename = sm.span_to_filename(krate_mod.spans.inner_span); - let data_id = id_from_hir_id(id, &self.save_ctxt); + let data_id = id_from_def_id(CRATE_DEF_ID.to_def_id()); let children = krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect(); let span = self.span_from_span(krate_mod.spans.inner_span); - let attrs = self.tcx.hir().attrs(id); + let attrs = self.tcx.hir().attrs(hir::CRATE_HIR_ID); self.dumper.dump_def( &Access { public: true, reachable: true }, @@ -1319,7 +1313,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // output the inferred type here? :shrug: hir::ArrayLen::Infer(..) => {} hir::ArrayLen::Body(anon_const) => self - .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + .nest_typeck_results(anon_const.def_id, |v| { v.visit_expr(&map.body(anon_const.body).value) }), } @@ -1361,7 +1355,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } } } - hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, def_id, .. }) => { let id = format!("${}", ex.hir_id); // walk arg and return types @@ -1375,7 +1369,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // walk the body let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(ex.hir_id), |v| { + self.nest_typeck_results(def_id, |v| { let body = map.body(body); v.process_formals(body.params, &id); v.visit_expr(&body.value) @@ -1389,7 +1383,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // output the inferred type here? :shrug: hir::ArrayLen::Infer(..) => {} hir::ArrayLen::Body(anon_const) => self - .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + .nest_typeck_results(anon_const.def_id, |v| { v.visit_expr(&map.body(anon_const.body).value) }), } diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index a8d82de02b7..a9a92cc4f62 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -21,7 +21,7 @@ use rustc_ast::util::comments::beautify_doc_string; use rustc_ast_pretty::pprust::attribute_to_string; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; @@ -318,7 +318,7 @@ impl<'tcx> SaveContext<'tcx> { qualname, value, parent: None, - children: def.variants.iter().map(|v| id_from_hir_id(v.hir_id, self)).collect(), + children: def.variants.iter().map(|v| id_from_def_id(v.def_id.to_def_id())).collect(), decl_id: None, docs: self.docs_for_attrs(attrs), sig: sig::item_signature(item, self), @@ -379,12 +379,11 @@ impl<'tcx> SaveContext<'tcx> { } } - pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: hir::HirId) -> Option<Def> { + pub fn get_field_data(&self, field: &hir::FieldDef<'_>, scope: LocalDefId) -> Option<Def> { let name = field.ident.to_string(); - let scope_def_id = self.tcx.hir().local_def_id(scope).to_def_id(); - let qualname = format!("::{}::{}", self.tcx.def_path_str(scope_def_id), field.ident); + let qualname = format!("::{}::{}", self.tcx.def_path_str(scope.to_def_id()), field.ident); filter!(self.span_utils, field.ident.span); - let field_def_id = self.tcx.hir().local_def_id(field.hir_id).to_def_id(); + let field_def_id = field.def_id.to_def_id(); let typ = self.tcx.type_of(field_def_id).to_string(); let id = id_from_def_id(field_def_id); @@ -398,7 +397,7 @@ impl<'tcx> SaveContext<'tcx> { name, qualname, value: typ, - parent: Some(id_from_def_id(scope_def_id)), + parent: Some(id_from_def_id(scope.to_def_id())), children: vec![], decl_id: None, docs: self.docs_for_attrs(attrs), @@ -409,12 +408,11 @@ impl<'tcx> SaveContext<'tcx> { // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> Option<Def> { + pub fn get_method_data(&self, owner_id: hir::OwnerId, ident: Ident, span: Span) -> Option<Def> { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); let (qualname, parent_scope, decl_id, docs, attributes) = - match self.tcx.impl_of_method(def_id) { + match self.tcx.impl_of_method(owner_id.to_def_id()) { Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) { Some(Node::Item(item)) => match item.kind { hir::ItemKind::Impl(hir::Impl { ref self_ty, .. }) => { @@ -427,8 +425,8 @@ impl<'tcx> SaveContext<'tcx> { let trait_id = self.tcx.trait_id_of_impl(impl_id); let mut docs = String::new(); let mut attrs = vec![]; - if let Some(Node::ImplItem(_)) = hir.find(hir_id) { - attrs = self.tcx.hir().attrs(hir_id).to_vec(); + if let Some(Node::ImplItem(_)) = hir.find(owner_id.into()) { + attrs = self.tcx.hir().attrs(owner_id.into()).to_vec(); docs = self.docs_for_attrs(&attrs); } @@ -452,29 +450,29 @@ impl<'tcx> SaveContext<'tcx> { _ => { span_bug!( span, - "Container {:?} for method {} not an impl?", + "Container {:?} for method {:?} not an impl?", impl_id, - hir_id + owner_id, ); } }, r => { span_bug!( span, - "Container {:?} for method {} is not a node item {:?}", + "Container {:?} for method {:?} is not a node item {:?}", impl_id, - hir_id, + owner_id, r ); } }, - None => match self.tcx.trait_of_item(def_id) { + None => match self.tcx.trait_of_item(owner_id.to_def_id()) { Some(def_id) => { let mut docs = String::new(); let mut attrs = vec![]; - if let Some(Node::TraitItem(_)) = self.tcx.hir().find(hir_id) { - attrs = self.tcx.hir().attrs(hir_id).to_vec(); + if let Some(Node::TraitItem(_)) = self.tcx.hir().find(owner_id.into()) { + attrs = self.tcx.hir().attrs(owner_id.into()).to_vec(); docs = self.docs_for_attrs(&attrs); } @@ -487,7 +485,7 @@ impl<'tcx> SaveContext<'tcx> { ) } None => { - debug!("could not find container for method {} at {:?}", hir_id, span); + debug!("could not find container for method {:?} at {:?}", owner_id, span); // This is not necessarily a bug, if there was a compilation error, // the typeck results we need might not exist. return None; @@ -501,7 +499,7 @@ impl<'tcx> SaveContext<'tcx> { Some(Def { kind: DefKind::Method, - id: id_from_def_id(def_id), + id: id_from_def_id(owner_id.to_def_id()), span: self.span_from_span(ident.span), name: ident.name.to_string(), qualname, @@ -669,7 +667,7 @@ impl<'tcx> SaveContext<'tcx> { match res { Res::Local(id) => { - Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id, self) }) + Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id) }) } Res::Def(HirDefKind::Trait, def_id) if fn_type(path_seg) => { Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) }) @@ -1033,18 +1031,15 @@ fn id_from_def_id(id: DefId) -> rls_data::Id { rls_data::Id { krate: id.krate.as_u32(), index: id.index.as_u32() } } -fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_>) -> rls_data::Id { - let def_id = scx.tcx.hir().opt_local_def_id(id); - def_id.map(|id| id_from_def_id(id.to_def_id())).unwrap_or_else(|| { - // Create a *fake* `DefId` out of a `HirId` by combining the owner - // `local_def_index` and the `local_id`. - // This will work unless you have *billions* of definitions in a single - // crate (very unlikely to actually happen). - rls_data::Id { - krate: LOCAL_CRATE.as_u32(), - index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(), - } - }) +fn id_from_hir_id(id: hir::HirId) -> rls_data::Id { + // Create a *fake* `DefId` out of a `HirId` by combining the owner + // `local_def_index` and the `local_id`. + // This will work unless you have *billions* of definitions in a single + // crate (very unlikely to actually happen). + rls_data::Id { + krate: LOCAL_CRATE.as_u32(), + index: id.owner.def_id.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(), + } } fn null_id() -> rls_data::Id { diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 5a1bcb8fdc8..979305547c1 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -25,7 +25,7 @@ // // FIXME where clauses need implementing, defs/refs in generics are mostly missing. -use crate::{id_from_def_id, id_from_hir_id, SaveContext}; +use crate::{id_from_def_id, SaveContext}; use rls_data::{SigElement, Signature}; @@ -34,6 +34,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir_pretty::id_to_string; use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string}; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> { @@ -71,7 +72,7 @@ pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> O } pub fn method_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, generics: &hir::Generics<'_>, m: &hir::FnSig<'_>, @@ -84,7 +85,7 @@ pub fn method_signature( } pub fn assoc_const_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Symbol, ty: &hir::Ty<'_>, default: Option<&hir::Expr<'_>>, @@ -97,7 +98,7 @@ pub fn assoc_const_signature( } pub fn assoc_type_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, bounds: Option<hir::GenericBounds<'_>>, default: Option<&hir::Ty<'_>>, @@ -112,7 +113,8 @@ pub fn assoc_type_signature( type Result = std::result::Result<Signature, &'static str>; trait Sig { - fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result; + type Parent; + fn make(&self, offset: usize, id: Option<Self::Parent>, scx: &SaveContext<'_>) -> Result; } fn extend_sig( @@ -148,6 +150,7 @@ fn text_sig(text: String) -> Signature { } impl<'hir> Sig for hir::Ty<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id); match self.kind { @@ -326,6 +329,7 @@ impl<'hir> Sig for hir::Ty<'hir> { } impl<'hir> Sig for hir::Item<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id()); @@ -391,7 +395,7 @@ impl<'hir> Sig for hir::Item<'hir> { text.push_str("fn "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push('('); for i in decl.inputs { @@ -441,7 +445,7 @@ impl<'hir> Sig for hir::Item<'hir> { hir::ItemKind::TyAlias(ref ty, ref generics) => { let text = "type ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" = "); let ty = ty.make(offset + sig.text.len(), id, scx)?; @@ -453,21 +457,21 @@ impl<'hir> Sig for hir::Item<'hir> { hir::ItemKind::Enum(_, ref generics) => { let text = "enum ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } hir::ItemKind::Struct(_, ref generics) => { let text = "struct ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } hir::ItemKind::Union(_, ref generics) => { let text = "union ".to_owned(); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push_str(" {}"); Ok(sig) } @@ -483,7 +487,7 @@ impl<'hir> Sig for hir::Item<'hir> { } text.push_str("trait "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; if !bounds.is_empty() { sig.text.push_str(": "); @@ -498,7 +502,7 @@ impl<'hir> Sig for hir::Item<'hir> { let mut text = String::new(); text.push_str("trait "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; if !bounds.is_empty() { sig.text.push_str(" = "); @@ -532,7 +536,8 @@ impl<'hir> Sig for hir::Item<'hir> { text.push_str(" const"); } - let generics_sig = generics.make(offset + text.len(), id, scx)?; + let generics_sig = + generics.make(offset + text.len(), Some(self.owner_id.def_id), scx)?; text.push_str(&generics_sig.text); text.push(' '); @@ -575,6 +580,7 @@ impl<'hir> Sig for hir::Item<'hir> { } impl<'hir> Sig for hir::Path<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let res = scx.get_path_res(id.ok_or("Missing id for Path")?); @@ -609,7 +615,8 @@ impl<'hir> Sig for hir::Path<'hir> { // This does not cover the where clause, which must be processed separately. impl<'hir> Sig for hir::Generics<'hir> { - fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { if self.params.is_empty() { return Ok(text_sig(String::new())); } @@ -624,7 +631,7 @@ impl<'hir> Sig for hir::Generics<'hir> { } param_text.push_str(param.name.ident().as_str()); defs.push(SigElement { - id: id_from_hir_id(param.hir_id, scx), + id: id_from_def_id(param.def_id.to_def_id()), start: offset + text.len(), end: offset + text.len() + param_text.as_str().len(), }); @@ -646,12 +653,13 @@ impl<'hir> Sig for hir::Generics<'hir> { } impl<'hir> Sig for hir::FieldDef<'hir> { - fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { let mut text = String::new(); text.push_str(&self.ident.to_string()); let defs = Some(SigElement { - id: id_from_hir_id(self.hir_id, scx), + id: id_from_def_id(self.def_id.to_def_id()), start: offset, end: offset + text.len(), }); @@ -666,13 +674,14 @@ impl<'hir> Sig for hir::FieldDef<'hir> { } impl<'hir> Sig for hir::Variant<'hir> { - fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { + type Parent = LocalDefId; + fn make(&self, offset: usize, parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result { let mut text = self.ident.to_string(); match self.data { hir::VariantData::Struct(fields, r) => { let id = parent_id.ok_or("Missing id for Variant's parent")?; let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -693,9 +702,9 @@ impl<'hir> Sig for hir::Variant<'hir> { text.push('}'); Ok(Signature { text, defs, refs }) } - hir::VariantData::Tuple(fields, id, _) => { + hir::VariantData::Tuple(fields, _, def_id) => { let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(def_id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -703,7 +712,7 @@ impl<'hir> Sig for hir::Variant<'hir> { let mut defs = vec![name_def]; let mut refs = vec![]; for f in fields { - let field_sig = f.make(offset + text.len(), Some(id), scx)?; + let field_sig = f.make(offset + text.len(), Some(def_id), scx)?; text.push_str(&field_sig.text); text.push_str(", "); defs.extend(field_sig.defs.into_iter()); @@ -712,9 +721,9 @@ impl<'hir> Sig for hir::Variant<'hir> { text.push(')'); Ok(Signature { text, defs, refs }) } - hir::VariantData::Unit(id, _) => { + hir::VariantData::Unit(_, def_id) => { let name_def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(def_id.to_def_id()), start: offset, end: offset + text.len(), }; @@ -725,6 +734,7 @@ impl<'hir> Sig for hir::Variant<'hir> { } impl<'hir> Sig for hir::ForeignItem<'hir> { + type Parent = hir::HirId; fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result { let id = Some(self.hir_id()); match self.kind { @@ -733,7 +743,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> { text.push_str("fn "); let mut sig = - name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?; + name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?; sig.text.push('('); for i in decl.inputs { @@ -797,25 +807,25 @@ fn name_and_generics( mut text: String, offset: usize, generics: &hir::Generics<'_>, - id: hir::HirId, + id: hir::OwnerId, name: Ident, scx: &SaveContext<'_>, ) -> Result { let name = name.to_string(); let def = SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: offset + text.len(), end: offset + text.len() + name.len(), }; text.push_str(&name); - let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; + let generics: Signature = generics.make(offset + text.len(), Some(id.def_id), scx)?; // FIXME where clause let text = format!("{}{}", text, generics.text); Ok(extend_sig(generics, text, vec![def], vec![])) } fn make_assoc_type_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, bounds: Option<hir::GenericBounds<'_>>, default: Option<&hir::Ty<'_>>, @@ -824,7 +834,7 @@ fn make_assoc_type_signature( let mut text = "type ".to_owned(); let name = ident.to_string(); let mut defs = vec![SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: text.len(), end: text.len() + name.len(), }]; @@ -837,7 +847,7 @@ fn make_assoc_type_signature( } if let Some(default) = default { text.push_str(" = "); - let ty_sig = default.make(text.len(), Some(id), scx)?; + let ty_sig = default.make(text.len(), Some(id.into()), scx)?; text.push_str(&ty_sig.text); defs.extend(ty_sig.defs.into_iter()); refs.extend(ty_sig.refs.into_iter()); @@ -847,7 +857,7 @@ fn make_assoc_type_signature( } fn make_assoc_const_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Symbol, ty: &hir::Ty<'_>, default: Option<&hir::Expr<'_>>, @@ -856,7 +866,7 @@ fn make_assoc_const_signature( let mut text = "const ".to_owned(); let name = ident.to_string(); let mut defs = vec![SigElement { - id: id_from_hir_id(id, scx), + id: id_from_def_id(id.to_def_id()), start: text.len(), end: text.len() + name.len(), }]; @@ -864,7 +874,7 @@ fn make_assoc_const_signature( text.push_str(&name); text.push_str(": "); - let ty_sig = ty.make(text.len(), Some(id), scx)?; + let ty_sig = ty.make(text.len(), Some(id.into()), scx)?; text.push_str(&ty_sig.text); defs.extend(ty_sig.defs.into_iter()); refs.extend(ty_sig.refs.into_iter()); @@ -878,7 +888,7 @@ fn make_assoc_const_signature( } fn make_method_signature( - id: hir::HirId, + id: hir::OwnerId, ident: Ident, generics: &hir::Generics<'_>, m: &hir::FnSig<'_>, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7b5fd6cc2a8..66b100c103e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1290,6 +1290,8 @@ options! { (default: no)"), drop_tracking: bool = (false, parse_bool, [TRACKED], "enables drop tracking in generators (default: no)"), + drop_tracking_mir: bool = (false, parse_bool, [TRACKED], + "enables drop tracking on MIR in generators (default: no)"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 0759b95bd94..c9b4ab0a38d 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -640,6 +640,7 @@ fn encode_ty<'tcx>( ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) | ty::Param(..) @@ -793,6 +794,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) | ty::Param(..) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0d446d654dc..00d1ff5ceed 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -490,6 +490,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"), + ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"), } // Only cache types that do not refer to an enclosing diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index d23b550621e..e44fd82ba22 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,6 +1,8 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; +#[cfg(doc)] +use super::trait_goals::structural_traits::*; use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -76,7 +78,7 @@ pub(super) enum CandidateSource { /// let _y = x.clone(); /// } /// ``` - AliasBound(usize), + AliasBound, } pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { @@ -98,52 +100,75 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; + // A type implements an `auto trait` if its components do as well. These components + // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `Copy` or `Clone` if its components are `Sized`. These components + // are given by built-in rules from [`instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. These + // components are given by built-in rules from [`instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A type is `PointerSized` if we can compute its layout, and that layout + // matches the layout of `usize`. fn consider_builtin_pointer_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` + // family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, ) -> QueryResult<'tcx>; + // `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // `Pointee` is always implemented. + // + // See the projection implementation for the `Metadata` types for all of + // the built-in types. For structs, the metadata type is given by the struct + // tail. fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A generator (that comes from an `async` desugaring) is known to implement + // `Future<Output = O>`, where `O` is given by the generator's return type + // that was computed during type-checking. fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + // A generator (that doesn't come from an `async` desugaring) is known to + // implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield, + // and return types of the generator computed during type-checking. fn consider_builtin_generator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -217,8 +242,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in winnowing. let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - // FIXME: This is broken if we care about the `usize` of `AliasBound` because the self type - // could be normalized to yet another projection with different item bounds. let normalized_candidates = self.assemble_and_evaluate_candidates(goal); for mut normalized_candidate in normalized_candidates { normalized_candidate.result = @@ -331,6 +354,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Param(_) @@ -342,15 +366,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Alias(_, alias_ty) => alias_ty, }; - for (i, (assumption, _)) in self + for (assumption, _) in self .tcx() .bound_explicit_item_bounds(alias_ty.def_id) .subst_iter_copied(self.tcx(), alias_ty.substs) - .enumerate() { match G::consider_assumption(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) + candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } Err(NoSolution) => (), } @@ -382,6 +405,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Param(_) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 278024b2276..a2c15123b4f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -40,12 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.push(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - let errors = self.select_where_possible(infcx); - if !errors.is_empty() { - return errors; - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { self.obligations .drain(..) .map(|obligation| FulfillmentError { @@ -144,4 +139,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.obligations.clone() } + + fn drain_unstalled_obligations( + &mut self, + _: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + unimplemented!() + } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index f44648c95d7..cbe64ae4f4e 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -13,14 +13,12 @@ // preserves universes and creates a unique var (in the highest universe) for each // appearance of a region. -// FIXME: `CanonicalVarValues` should be interned and `Copy`. - // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. use std::mem; use rustc_hir::def_id::DefId; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues}; +use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; @@ -141,17 +139,6 @@ type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; -pub trait TyCtxtExt<'tcx> { - fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx>; -} - -impl<'tcx> TyCtxtExt<'tcx> for TyCtxt<'tcx> { - fn evaluate_goal(self, goal: CanonicalGoal<'tcx>) -> QueryResult<'tcx> { - let mut search_graph = search_graph::SearchGraph::new(self); - EvalCtxt::evaluate_canonical_goal(self, &mut search_graph, goal) - } -} - pub trait InferCtxtEvalExt<'tcx> { /// Evaluates a goal from **outside** of the trait solver. /// @@ -194,6 +181,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.infcx.tcx } + /// The entry point of the solver. + /// + /// This function deals with (coinductive) cycles, overflow, and caching + /// and then calls [`EvalCtxt::compute_goal`] which contains the actual + /// logic of the solver. + /// + /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] + /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// outside of it. #[instrument(level = "debug", skip(tcx, search_graph), ret)] fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, @@ -227,7 +223,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let external_constraints = take_external_constraints(self.infcx)?; Ok(self.infcx.canonicalize_response(Response { - var_values: self.var_values.clone(), + var_values: self.var_values, external_constraints, certainty, })) @@ -337,15 +333,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // That won't actually reflect in the query response, so it seems moot. self.make_canonical_response(Certainty::AMBIGUOUS) } else { - self.infcx.probe(|_| { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(goal.predicate.a, goal.predicate.b)?; - self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|pred| pred.into()).collect(), - ) - }) + let InferOk { value: (), obligations } = self + .infcx + .at(&ObligationCause::dummy(), goal.param_env) + .sub(goal.predicate.a, goal.predicate.b)?; + self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|pred| pred.into()).collect(), + ) } } @@ -378,22 +372,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &mut self, goal: Goal<'tcx, ty::GenericArg<'tcx>>, ) -> QueryResult<'tcx> { - self.infcx.probe(|_| { - match crate::traits::wf::unnormalized_obligations( - self.infcx, - goal.param_env, - goal.predicate, - ) { - Some(obligations) => self.evaluate_all_and_make_canonical_response( - obligations.into_iter().map(|o| o.into()).collect(), - ), - None => self.make_canonical_response(Certainty::AMBIGUOUS), - } - }) + match crate::traits::wf::unnormalized_obligations( + self.infcx, + goal.param_env, + goal.predicate, + ) { + Some(obligations) => self.evaluate_all_and_make_canonical_response( + obligations.into_iter().map(|o| o.into()).collect(), + ), + None => self.make_canonical_response(Certainty::AMBIGUOUS), + } } } impl<'tcx> EvalCtxt<'_, 'tcx> { + // Recursively evaluates a list of goals to completion, returning the certainty + // of all of the goals. fn evaluate_all( &mut self, mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, @@ -430,6 +424,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + // Recursively evaluates a list of goals to completion, making a query response. + // + // This is just a convenient way of calling [`EvalCtxt::evaluate_all`], + // then [`EvalCtxt::make_canonical_response`]. fn evaluate_all_and_make_canonical_response( &mut self, goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, @@ -483,32 +481,11 @@ pub(super) fn response_no_constraints<'tcx>( goal: Canonical<'tcx, impl Sized>, certainty: Certainty, ) -> QueryResult<'tcx> { - let var_values = goal - .variables - .iter() - .enumerate() - .map(|(i, info)| match info.kind { - CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into())).into() - } - CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(i), - kind: ty::BrAnon(i as u32, None), - }; - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() - } - CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => tcx - .mk_const(ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), ty) - .into(), - }) - .collect(); - Ok(Canonical { max_universe: goal.max_universe, variables: goal.variables, value: Response { - var_values: CanonicalVarValues { var_values }, + var_values: CanonicalVarValues::make_identity(tcx, goal.variables), external_constraints: Default::default(), certainty, }, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index b583705ac43..b175a6dde17 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -28,8 +28,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // To only compute normalization once for each projection we only // normalize if the expected term is an unconstrained inference variable. // - // E.g. for `<T as Trait>::Assoc = u32` we recursively compute the goal - // `exists<U> <T as Trait>::Assoc = U` and then take the resulting type for + // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal + // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for // `U` and equate it with `u32`. This means that we don't need a separate // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { @@ -93,24 +93,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { if t.needs_infer() { if ty::Term::from(t) == self.term { - ControlFlow::BREAK + ControlFlow::Break(()) } else { t.super_visit_with(self) } } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { if c.needs_infer() { if ty::Term::from(c) == self.term { - ControlFlow::BREAK + ControlFlow::Break(()) } else { c.super_visit_with(self) } } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -171,7 +171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::BuiltinImpl, _) - | (CandidateSource::AliasBound(_), _) => unimplemented!(), + | (CandidateSource::AliasBound, _) => unimplemented!(), } } } @@ -296,7 +296,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() + && poly_projection_pred.projection_def_id() == goal.predicate.def_id() + { ecx.infcx.probe(|_| { let assumption_projection_pred = ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); @@ -414,6 +416,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Foreign(..) => tcx.types.unit, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs index 730a8e61258..80a388b8498 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -95,6 +95,7 @@ impl<'tcx> ProvisionalCache<'tcx> { } pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> { + // FIXME: Responses should probably be `Copy` as well self.entries[entry_index].response.clone() } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d74857dc4b4..1ea8fb8fd3d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -65,7 +65,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx> { - if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() + && poly_trait_pred.def_id() == goal.predicate.def_id() + { // FIXME: Constness and polarity ecx.infcx.probe(|_| { let assumption_trait_pred = @@ -320,7 +322,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { match (candidate.source, other.source) { (CandidateSource::Impl(_), _) | (CandidateSource::ParamEnv(_), _) - | (CandidateSource::AliasBound(_), _) + | (CandidateSource::AliasBound, _) | (CandidateSource::BuiltinImpl, _) => unimplemented!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 6cab0bc6a4b..5007a019e18 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -57,6 +57,8 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) } + ty::GeneratorWitnessMIR(..) => todo!(), + // For `PhantomData<T>`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), @@ -88,6 +90,7 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -173,6 +176,8 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::GeneratorWitness(types) => { Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) } + + ty::GeneratorWitnessMIR(..) => todo!(), } } @@ -215,6 +220,7 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( | ty::Dynamic(_, _, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(_) | ty::Alias(_, _) diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 61d09189798..e26bef0b8b7 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -40,15 +40,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.obligations.insert(obligation); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { // any remaining obligations are errors self.obligations .iter() @@ -143,6 +135,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { errors } + fn drain_unstalled_obligations( + &mut self, + _: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + unimplemented!() + } + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.obligations.iter().cloned().collect() } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ecee0bf7a6d..61f508a7a07 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -696,7 +696,9 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { // This should only be created when checking whether we have to check whether some // auto trait impl applies. There will never be multiple impls, so we can just // act as if it were a local type here. - ty::GeneratorWitness(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), + ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(..) => { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } ty::Alias(ty::Opaque, ..) => { // This merits some explanation. // Normally, opaque types are not involved when performing diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 98917430d24..e9842b2cba5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -101,6 +101,18 @@ pub trait InferCtxtExt<'tcx> { } pub trait TypeErrCtxtExt<'tcx> { + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + fn report_overflow_error<T>( &self, predicate: &T, @@ -484,6 +496,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, { + let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); + mutate(&mut err); + err.emit(); + + self.tcx.sess.abort_if_errors(); + bug!(); + } + + fn build_overflow_error<T>( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + { let predicate = self.resolve_vars_if_possible(predicate.clone()); let mut pred_str = predicate.to_string(); @@ -511,11 +543,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - mutate(&mut err); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); + err } /// Reports that an overflow has occurred and halts compilation. We @@ -1891,6 +1919,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Generator(..) => Some(16), ty::Foreign(..) => Some(17), ty::GeneratorWitness(..) => Some(18), + ty::GeneratorWitnessMIR(..) => Some(19), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index bf5e77e6ce1..ee0c07e15a3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -399,7 +399,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// param for cleaner code. fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, - hir_id: HirId, + item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, msg: &str, err: &mut Diagnostic, @@ -418,7 +418,6 @@ fn suggest_restriction<'tcx>( { return; } - let Some(item_id) = hir_id.as_owner() else { return; }; let generics = tcx.generics_of(item_id); // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((param, bound_str, fn_sig)) = @@ -523,7 +522,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, - body_id: LocalDefId, + mut body_id: LocalDefId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -536,9 +535,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. - let mut body_id = body_id; while let Some(node) = self.tcx.hir().find_by_def_id(body_id) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(body_id); match node { hir::Node::Item(hir::Item { ident, @@ -549,7 +546,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Restricting `Self` for a single method. suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "`Self`", err, @@ -569,7 +566,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred, + self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred, None, ); return; @@ -591,7 +588,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -611,7 +608,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( self.tcx, - hir_id, + body_id, &generics, "the associated type", err, @@ -2226,7 +2223,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, _) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2256,7 +2253,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); match *ty.kind() { - ty::Generator(did, ..) => { + ty::Generator(did, ..) | ty::GeneratorWitnessMIR(did, ..) => { generator = generator.or(Some(did)); outer_generator = Some(did); } @@ -2345,6 +2342,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => return false, }; + let generator_within_in_progress_typeck = match &self.typeck_results { + Some(t) => t.hir_owner.to_def_id() == generator_did_root, + _ => false, + }; + let mut interior_or_upvar_span = None; let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); @@ -2364,6 +2366,35 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { *span, Some((*scope_span, *yield_span, *expr, from_awaited_ty)), )); + + if interior_or_upvar_span.is_none() && generator_data.is_foreign() { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span, None)); + } + } else if self.tcx.sess.opts.unstable_opts.drop_tracking_mir + // Avoid disclosing internal information to downstream crates. + && generator_did.is_local() + // Try to avoid cycles. + && !generator_within_in_progress_typeck + { + let generator_info = &self.tcx.mir_generator_witnesses(generator_did); + debug!(?generator_info); + + 'find_source: for (variant, source_info) in + generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) + { + debug!(?variant); + for &local in variant { + let decl = &generator_info.field_tys[local]; + debug!(?decl); + if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( + decl.source_info.span, + Some((None, source_info.span, None, from_awaited_ty)), + )); + break 'find_source; + } + } + } } if interior_or_upvar_span.is_none() { @@ -3012,6 +3043,20 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } err.note(msg.trim_end_matches(", ")) } + ty::GeneratorWitnessMIR(def_id, substs) => { + use std::fmt::Write; + + // FIXME: this is kind of an unusual format for rustc, can we make it more clear? + // Maybe we should just remove this note altogether? + // FIXME: only print types which don't meet the trait requirement + let mut msg = + "required because it captures the following types: ".to_owned(); + for bty in tcx.generator_hidden_types(*def_id) { + let ty = bty.subst(tcx, substs); + write!(msg, "`{}`, ", ty).unwrap(); + } + err.note(msg.trim_end_matches(", ")) + } ty::Generator(def_id, _, _) => { let sp = self.tcx.def_span(def_id); @@ -3759,13 +3804,13 @@ fn hint_missing_borrow<'tcx>( err: &mut Diagnostic, ) { let found_args = match found.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), + ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) } }; let expected_args = match expected.kind() { - ty::FnPtr(f) => f.inputs().skip_binder().iter(), + ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(), kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } @@ -3776,12 +3821,12 @@ fn hint_missing_borrow<'tcx>( let args = fn_decl.inputs.iter().map(|ty| ty); - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) { - let mut refs = 0; + fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) { + let mut refs = vec![]; - while let ty::Ref(_, new_ty, _) = ty.kind() { + while let ty::Ref(_, new_ty, mutbl) = ty.kind() { ty = *new_ty; - refs += 1; + refs.push(*mutbl); } (ty, refs) @@ -3795,11 +3840,21 @@ fn hint_missing_borrow<'tcx>( let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg); if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() { - if found_refs < expected_refs { - to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs))); - } else if found_refs > expected_refs { + // FIXME: This could handle more exotic cases like mutability mismatches too! + if found_refs.len() < expected_refs.len() + && found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..] + { + to_borrow.push(( + arg.span.shrink_to_lo(), + expected_refs[..expected_refs.len() - found_refs.len()] + .iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::<Vec<_>>() + .join(""), + )); + } else if found_refs.len() > expected_refs.len() { let mut span = arg.span.shrink_to_lo(); - let mut left = found_refs - expected_refs; + let mut left = found_refs.len() - expected_refs.len(); let mut ty = arg; while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { span = span.with_hi(mut_ty.ty.span.lo()); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5a58d37e183..6c18bf8d22d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -132,14 +132,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - { - let errors = self.select_where_possible(infcx); - if !errors.is_empty() { - return errors; - } - } - + fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> { self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect() } @@ -148,6 +141,55 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(selcx) } + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>> { + let mut processor = DrainProcessor { removed_predicates: Vec::new(), infcx }; + let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut processor); + assert!(outcome.errors.is_empty()); + return processor.removed_predicates; + + struct DrainProcessor<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + removed_predicates: Vec<PredicateObligation<'tcx>>, + } + + impl<'tcx> ObligationProcessor for DrainProcessor<'_, 'tcx> { + type Obligation = PendingPredicateObligation<'tcx>; + type Error = !; + type OUT = Outcome<Self::Obligation, Self::Error>; + + fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { + pending_obligation + .stalled_on + .iter() + .any(|&var| self.infcx.ty_or_const_infer_var_changed(var)) + } + + fn process_obligation( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult<PendingPredicateObligation<'tcx>, !> { + assert!(self.needs_process_obligation(pending_obligation)); + self.removed_predicates.push(pending_obligation.obligation.clone()); + ProcessResult::Changed(vec![]) + } + + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) -> Result<(), !> + where + I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, + { + self.removed_predicates.extend(cycle.map(|c| c.obligation.clone())); + Ok(()) + } + } + } + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fbc7eccedc8..a11c5e81969 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1605,6 +1605,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Tuple(..) // Integers and floats always have `u8` as their discriminant. @@ -1654,6 +1655,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never // Extern types have unit metadata, according to RFC 2850 | ty::Foreign(_) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 0f21813bc40..455b53bfb7d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -31,6 +31,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::RawPtr(_) | ty::Ref(..) | ty::Str diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 09b58894d30..f183248f2d0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,7 +1,9 @@ use rustc_middle::ty; +use rustc_session::config::TraitSolver; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; +use crate::solve::{Certainty, Goal, InferCtxtEvalExt, MaybeCause}; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; pub trait InferCtxtExt<'tcx> { @@ -77,12 +79,38 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { _ => obligation.param_env.without_const(), }; - let c_pred = self - .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + if self.tcx.sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + let c_pred = self.canonicalize_query_keep_static( + param_env.and(obligation.predicate), + &mut _orig_values, + ); + self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + } else { + self.probe(|snapshot| { + if let Ok((_, certainty)) = + self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate)) + { + match certainty { + Certainty::Yes => { + if self.opaque_types_added_in_snapshot(snapshot) { + Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) + } else if self.region_constraints_added_in_snapshot(snapshot).is_some() + { + Ok(EvaluationResult::EvaluatedToOkModuloRegions) + } else { + Ok(EvaluationResult::EvaluatedToOk) + } + } + Certainty::Maybe(MaybeCause::Ambiguity) => { + Ok(EvaluationResult::EvaluatedToAmbig) + } + Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical), + } + } else { + Ok(EvaluationResult::EvaluatedToErr) + } + }) + } } // Helper function that canonicalizes and runs the query. If an @@ -92,6 +120,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. match self.evaluate_obligation(obligation) { Ok(result) => result, Err(OverflowError::Canonical) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 27247271d1f..1b2533a5cf6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -216,12 +216,16 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let substs = substs.try_fold_with(self)?; let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { - self.infcx.err_ctxt().report_overflow_error( - &ty, - self.cause.span, - true, - |_| {}, - ); + // A closure or generator may have itself as in its upvars. + // This should be checked handled by the recursion check for opaque + // types, but we may end up here before that check can happen. + // In that case, we delay a bug to mark the trip, and continue without + // revealing the opaque. + self.infcx + .err_ctxt() + .build_overflow_error(&ty, self.cause.span, true) + .delay_as_bug(); + return ty.try_super_fold_with(self); } let generic_ty = self.tcx().bound_type_of(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 87d574ff107..52f4d29181d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -765,7 +765,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::Tuple(_) - | ty::GeneratorWitness(_) => { + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) => { // These are built-in, and cannot have a custom `impl const Destruct`. candidates.vec.push(ConstDestructCandidate(None)); } @@ -826,6 +827,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Alias(..) | ty::Param(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 82a59831be3..61d3531cfc4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_middle::ty::{ self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef, - ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, + ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitable, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -1285,6 +1285,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::GeneratorWitness(tys) => { stack.extend(tcx.erase_late_bound_regions(tys).to_vec()); } + ty::GeneratorWitnessMIR(def_id, substs) => { + let tcx = self.tcx(); + stack.extend(tcx.generator_hidden_types(def_id).map(|bty| { + let ty = bty.subst(tcx, substs); + debug_assert!(!ty.has_late_bound_regions()); + ty + })) + } // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1d23634b6aa..efd21b979ce 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2066,6 +2066,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Array(..) | ty::Closure(..) | ty::Never @@ -2182,6 +2183,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + let hidden_types = bind_generator_hidden_types_above( + self.infcx, + def_id, + substs, + obligation.predicate.bound_vars(), + ); + Where(hidden_types) + } + ty::Closure(_, substs) => { // (*) binder moved here let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); @@ -2279,6 +2290,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { types.map_bound(|types| types.to_vec()) } + ty::GeneratorWitnessMIR(def_id, ref substs) => { + bind_generator_hidden_types_above(self.infcx, def_id, substs, t.bound_vars()) + } + // For `PhantomData<T>`, we pass `T`. ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()), @@ -2921,3 +2936,56 @@ pub enum ProjectionMatchesProjection { Ambiguous, No, } + +/// Replace all regions inside the generator interior with late bound regions. +/// Note that each region slot in the types gets a new fresh late bound region, which means that +/// none of the regions inside relate to any other, even if typeck had previously found constraints +/// that would cause them to be related. +#[instrument(level = "trace", skip(infcx), ret)] +fn bind_generator_hidden_types_above<'tcx>( + infcx: &InferCtxt<'tcx>, + def_id: DefId, + substs: ty::SubstsRef<'tcx>, + bound_vars: &ty::List<ty::BoundVariableKind>, +) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { + let tcx = infcx.tcx; + let mut seen_tys = FxHashSet::default(); + + let considering_regions = infcx.considering_regions; + + let num_bound_variables = bound_vars.len() as u32; + let mut counter = num_bound_variables; + + let hidden_types: Vec<_> = tcx + .generator_hidden_types(def_id) + // Deduplicate tys to avoid repeated work. + .filter(|bty| seen_tys.insert(*bty)) + .map(|bty| { + let mut ty = bty.subst(tcx, substs); + + // Only remap erased regions if we use them. + if considering_regions { + ty = tcx.fold_regions(ty, |mut r, current_depth| { + if let ty::ReErased = r.kind() { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(counter), + kind: ty::BrAnon(counter, None), + }; + counter += 1; + r = tcx.mk_region(ty::ReLateBound(current_depth, br)); + } + r + }) + } + + ty + }) + .collect(); + if considering_regions { + debug_assert!(!hidden_types.has_erased_regions()); + } + let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.iter().chain( + (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))), + )); + ty::Binder::bind_with_vars(hidden_types, bound_vars) +} diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index f398fb06c18..69b965f3a38 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -101,7 +101,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Closure(..) => { return ControlFlow::Break(ty); } - ty::Generator(..) | ty::GeneratorWitness(..) => { + ty::Generator(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => { return ControlFlow::Break(ty); } ty::FnDef(..) => { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 767e31ddf78..7c5e147a950 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -551,6 +551,7 @@ impl<'tcx> WfPredicates<'tcx> { | ty::Error(_) | ty::Str | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Never | ty::Param(_) | ty::Bound(..) diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9712abb708f..3a254105162 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -343,6 +343,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { substs.lower_into(interner), ), ty::GeneratorWitness(_) => unimplemented!(), + ty::GeneratorWitnessMIR(..) => unimplemented!(), ty::Never => chalk_ir::TyKind::Never, ty::Tuple(types) => { chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner)) diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index f76386fa720..13d83b92689 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -8,13 +8,10 @@ pub(crate) mod lowering; use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::IndexVec; - use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; use rustc_middle::traits::ChalkRustInterner; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{self, ParamTy, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, @@ -100,11 +97,13 @@ pub(crate) fn evaluate_goal<'tcx>( binders: chalk_ir::CanonicalVarKinds<_>| { use rustc_middle::infer::canonical::CanonicalVarInfo; - let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new(); let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params); - subst.as_slice(interner).iter().for_each(|p| { - var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor)); - }); + let var_values = tcx.mk_substs( + subst + .as_slice(interner) + .iter() + .map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)), + ); let variables: Vec<_> = binders .iter(interner) .map(|var| { @@ -159,8 +158,7 @@ pub(crate) fn evaluate_goal<'tcx>( max_universe: ty::UniverseIndex::from_usize(0), variables: obligation.variables, value: QueryResponse { - var_values: CanonicalVarValues { var_values: IndexVec::new() } - .make_identity(tcx), + var_values: CanonicalVarValues::dummy(), region_constraints: QueryRegionConstraints::default(), certainty: Certainty::Ambiguous, opaque_types: vec![], diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index c0da8a8169e..6f81d343e0f 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -4,7 +4,7 @@ // general routines. use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_infer::traits::FulfillmentErrorCode; +use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 481b56e111e..8b7f8033bfa 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -164,7 +164,8 @@ fn dtorck_constraint_for_ty<'tcx>( | ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(_) - | ty::GeneratorWitness(..) => { + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) => { // these types never have a destructor } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 0f25579c7bf..378cd5a99ed 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -470,7 +470,10 @@ fn layout_of_uncached<'tcx>( return Err(LayoutError::Unknown(ty)); } - ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } @@ -640,7 +643,7 @@ fn generator_layout<'tcx>( let promoted_layouts = ineligible_locals .iter() - .map(|local| subst_field(info.field_tys[local])) + .map(|local| subst_field(info.field_tys[local].ty)) .map(|ty| tcx.mk_maybe_uninit(ty)) .map(|ty| cx.layout_of(ty)); let prefix_layouts = substs @@ -710,7 +713,7 @@ fn generator_layout<'tcx>( Assigned(_) => bug!("assignment does not match variant"), Ineligible(_) => false, }) - .map(|local| subst_field(info.field_tys[*local])); + .map(|local| subst_field(info.field_tys[*local].ty)); let mut variant = univariant_uninterned( cx, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 0df060fc5fb..cd1475391a4 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -109,6 +109,13 @@ where for component in components { match *component.kind() { + // The information required to determine whether a generator has drop is + // computed on MIR, while this very method is used to build MIR. + // To avoid cycles, we consider that generators always require drop. + ty::Generator(..) if tcx.sess.opts.unstable_opts.drop_tracking_mir => { + return Some(Err(AlwaysRequiresDrop)); + } + _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), ty::Closure(_, substs) => { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 77986ad4861..89abffebdc6 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -16,7 +16,13 @@ fn sized_constraint_for_ty<'tcx>( Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], - Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => { + Str + | Dynamic(..) + | Slice(_) + | Foreign(..) + | Error(_) + | GeneratorWitness(..) + | GeneratorWitnessMIR(..) => { // these are never sized - return the target type vec![ty] } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 44004cb0be1..d5de457a82c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -265,6 +265,9 @@ bitflags! { /// Does this value have `InferConst::Fresh`? const HAS_CT_FRESH = 1 << 21; + + /// Does this have `Generator` or `GeneratorWitness`? + const HAS_TY_GENERATOR = 1 << 22; } } diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 5f29588ae4d..e7bb3055373 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -160,6 +160,32 @@ pub enum TyKind<I: Interner> { /// ``` GeneratorWitness(I::BinderListTy), + /// A type representing the types stored inside a generator. + /// This should only appear as part of the `GeneratorSubsts`. + /// + /// Unlike upvars, the witness can reference lifetimes from + /// inside of the generator itself. To deal with them in + /// the type of the generator, we convert them to higher ranked + /// lifetimes bound by the witness itself. + /// + /// This variant is only using when `drop_tracking_mir` is set. + /// This contains the `DefId` and the `SubstRef` of the generator. + /// The actual witness types are computed on MIR by the `mir_generator_witnesses` query. + /// + /// Looking at the following example, the witness for this generator + /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`: + /// + /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?) + /// #![feature(generators)] + /// |a| { + /// let x = &vec![3]; + /// yield a; + /// yield x[0]; + /// } + /// # ; + /// ``` + GeneratorWitnessMIR(I::DefId, I::SubstsRef), + /// The never type `!`. Never, @@ -241,6 +267,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize { Placeholder(_) => 23, Infer(_) => 24, Error(_) => 25, + GeneratorWitnessMIR(_, _) => 26, } } @@ -266,6 +293,7 @@ impl<I: Interner> Clone for TyKind<I> { Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), + GeneratorWitnessMIR(d, s) => GeneratorWitnessMIR(d.clone(), s.clone()), Never => Never, Tuple(t) => Tuple(t.clone()), Alias(k, p) => Alias(*k, p.clone()), @@ -303,6 +331,10 @@ impl<I: Interner> PartialEq for TyKind<I> { a_d == b_d && a_s == b_s && a_m == b_m } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, + ( + &GeneratorWitnessMIR(ref a_d, ref a_s), + &GeneratorWitnessMIR(ref b_d, ref b_s), + ) => a_d == b_d && a_s == b_s, (Tuple(a_t), Tuple(b_t)) => a_t == b_t, (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p, (Param(a_p), Param(b_p)) => a_p == b_p, @@ -360,6 +392,13 @@ impl<I: Interner> Ord for TyKind<I> { a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m))) } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g), + ( + &GeneratorWitnessMIR(ref a_d, ref a_s), + &GeneratorWitnessMIR(ref b_d, ref b_s), + ) => match Ord::cmp(a_d, b_d) { + Ordering::Equal => Ord::cmp(a_s, b_s), + cmp => cmp, + }, (Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t), (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i.cmp(b_i).then_with(|| a_p.cmp(b_p)), (Param(a_p), Param(b_p)) => a_p.cmp(b_p), @@ -421,6 +460,10 @@ impl<I: Interner> hash::Hash for TyKind<I> { m.hash(state) } GeneratorWitness(g) => g.hash(state), + GeneratorWitnessMIR(d, s) => { + d.hash(state); + s.hash(state); + } Tuple(t) => t.hash(state), Alias(i, p) => { i.hash(state); @@ -461,6 +504,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> { Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s), Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m), GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g), + GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s), Never => f.write_str("Never"), Tuple(t) => f.debug_tuple_field1_finish("Tuple", t), Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a), @@ -559,6 +603,10 @@ where GeneratorWitness(b) => e.emit_enum_variant(disc, |e| { b.encode(e); }), + GeneratorWitnessMIR(def_id, substs) => e.emit_enum_variant(disc, |e| { + def_id.encode(e); + substs.encode(e); + }), Never => e.emit_enum_variant(disc, |_| {}), Tuple(substs) => e.emit_enum_variant(disc, |e| { substs.encode(e); @@ -641,6 +689,7 @@ where 23 => Placeholder(Decodable::decode(d)), 24 => Infer(Decodable::decode(d)), 25 => Error(Decodable::decode(d)), + 26 => GeneratorWitnessMIR(Decodable::decode(d), Decodable::decode(d)), _ => panic!( "{}", format!( @@ -742,6 +791,10 @@ where GeneratorWitness(b) => { b.hash_stable(__hcx, __hasher); } + GeneratorWitnessMIR(def_id, substs) => { + def_id.hash_stable(__hcx, __hasher); + substs.hash_stable(__hcx, __hasher); + } Never => {} Tuple(substs) => { substs.hash_stable(__hcx, __hasher); |
