diff options
Diffstat (limited to 'compiler')
241 files changed, 2813 insertions, 2263 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 90ddeec4bc7..5cb79d9eea5 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -22,8 +22,6 @@ #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] #![deny(unsafe_op_in_unsafe_fn)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine. diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 76d838308b4..356e9fef439 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -18,8 +18,6 @@ #![feature(min_specialization)] #![feature(negative_impls)] #![feature(stmt_expr_attributes)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 3742cf9d881..fd717e82d26 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -205,7 +205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); hir::InlineAsmOperand::SymStatic { path, def_id } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index d310f72f7a3..865a56b2c1f 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -85,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ty = l .ty .as_ref() - .map(|t| self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); + .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 6ccf39b0cb1..d1ba93f0675 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -218,7 +218,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &delegation.qself, &delegation.path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); let block = delegation.body.as_deref(); diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index ec92afee47a..62253585695 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,4 +1,6 @@ -use rustc_errors::{codes::*, DiagnosticArgFromDisplay}; +use rustc_errors::{ + codes::*, AddToDiagnostic, Diagnostic, DiagnosticArgFromDisplay, SubdiagnosticMessageOp, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -38,14 +40,8 @@ pub struct InvalidAbi { pub struct InvalidAbiReason(pub &'static str); -impl rustc_errors::AddToDiagnostic for InvalidAbiReason { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) - where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, - { +impl AddToDiagnostic for InvalidAbiReason { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { #[allow(rustc::untranslatable_diagnostic)] diag.note(self.0); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c4798887637..942aae3d536 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -99,7 +99,7 @@ impl<'hir> LoweringContext<'_, 'hir> { seg, ParamMode::Optional, ParenthesizedGenericArgs::Err, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, // Method calls can't have bound modifiers None, @@ -141,13 +141,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(expr, ty) => { let expr = self.lower_expr(expr); let ty = - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ohs) => { @@ -267,7 +267,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); hir::ExprKind::Path(qpath) @@ -295,7 +295,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( self.lower_ty( container, - &ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), + ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), ), self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), ), @@ -314,7 +314,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, )), self.arena @@ -1241,7 +1241,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); // Destructure like a tuple struct. @@ -1261,7 +1261,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); // Destructure like a unit struct. @@ -1286,7 +1286,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); let fields_omitted = match &se.rest { diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 993ddf00eb5..11aa6b250b1 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -15,7 +15,7 @@ struct NodeCollector<'a, 'hir> { bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>, /// Outputs - nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, + nodes: IndexVec<ItemLocalId, ParentedNode<'hir>>, parenting: LocalDefIdMap<ItemLocalId>, /// The parent of this node @@ -29,16 +29,19 @@ pub(super) fn index_hir<'hir>( tcx: TyCtxt<'hir>, item: hir::OwnerNode<'hir>, bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>, -) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, LocalDefIdMap<ItemLocalId>) { - let mut nodes = IndexVec::new(); + num_nodes: usize, +) -> (IndexVec<ItemLocalId, ParentedNode<'hir>>, LocalDefIdMap<ItemLocalId>) { + let zero_id = ItemLocalId::new(0); + let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) }; + let mut nodes = IndexVec::from_elem_n(err_node, num_nodes); // This node's parent should never be accessed: the owner's parent is computed by the // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is // used. - nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() })); + nodes[zero_id] = ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }; let mut collector = NodeCollector { tcx, owner: item.def_id(), - parent_node: ItemLocalId::new(0), + parent_node: zero_id, nodes, bodies, parenting: Default::default(), @@ -54,6 +57,14 @@ pub(super) fn index_hir<'hir>( OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item), }; + for (local_id, node) in collector.nodes.iter_enumerated() { + if let Node::Err(span) = node.node { + let hir_id = HirId { owner: item.def_id(), local_id }; + let msg = format!("ID {hir_id} not encountered when visiting item HIR"); + tcx.dcx().span_delayed_bug(*span, msg); + } + } + (collector.nodes, collector.parenting) } @@ -88,7 +99,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } } - self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node }); + self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; } fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) { @@ -254,6 +265,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) { + // FIXME: walk path segment with `path_segment.hir_id` parent. self.insert(path_segment.ident.span, path_segment.hir_id, Node::PathSegment(path_segment)); intravisit::walk_path_segment(self, path_segment); } @@ -348,4 +360,23 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.visit_nested_foreign_item(id); } + + fn visit_where_predicate(&mut self, predicate: &'hir WherePredicate<'hir>) { + match predicate { + WherePredicate::BoundPredicate(pred) => { + self.insert(pred.span, pred.hir_id, Node::WhereBoundPredicate(pred)); + self.with_parent(pred.hir_id, |this| { + intravisit::walk_where_predicate(this, predicate) + }) + } + _ => intravisit::walk_where_predicate(self, predicate), + } + } + + fn visit_array_length(&mut self, len: &'hir ArrayLen) { + match len { + ArrayLen::Infer(inf) => self.insert(inf.span, inf.hir_id, Node::ArrayLenInfer(inf)), + ArrayLen::Body(..) => intravisit::walk_array_len(self, len), + } + } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7b81ed4875c..fb52f9cf58f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -189,7 +189,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) }, @@ -218,7 +218,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, decl) = - this.lower_generics(generics, header.constness, id, &itctx, |this| { + this.lower_generics(generics, header.constness, id, itctx, |this| { this.lower_fn_decl( decl, id, @@ -263,7 +263,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { let guar = this.dcx().span_delayed_bug( @@ -274,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some(ty) => this.lower_ty( ty, - &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false }, + ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false }, ), }, ); @@ -285,7 +285,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.arena.alloc_from_iter( enum_definition.variants.iter().map(|x| this.lower_variant(x)), @@ -299,7 +299,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), ); hir::ItemKind::Struct(struct_def, generics) @@ -309,7 +309,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), ); hir::ItemKind::Union(vdata, generics) @@ -339,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, *constness, id, &itctx, |this| { + self.lower_generics(ast_generics, *constness, id, itctx, |this| { let modifiers = TraitBoundModifiers { constness: match *constness { Const::Yes(span) => BoundConstness::Maybe(span), @@ -354,13 +354,13 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_trait_ref( modifiers, trait_ref, - &ImplTraitContext::Disallowed(ImplTraitPosition::Trait), + ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) }); let lowered_ty = this.lower_ty( ty, - &ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), + ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), ); (trait_ref, lowered_ty) @@ -400,11 +400,11 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, constness, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let bounds = this.lower_param_bounds( bounds, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ); let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), @@ -420,11 +420,11 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.lower_param_bounds( bounds, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) }, ); @@ -464,7 +464,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body: Option<&Expr>, impl_trait_position: ImplTraitPosition, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(impl_trait_position)); + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position)); (ty, self.lower_const_body(span, body)) } @@ -569,7 +569,12 @@ impl<'hir> LoweringContext<'_, 'hir> { }); } - let path = if trees.is_empty() && !prefix.segments.is_empty() { + // Condition should match `build_reduced_graph_for_use_tree`. + let path = if trees.is_empty() + && !(prefix.segments.is_empty() + || prefix.segments.len() == 1 + && prefix.segments[0].ident.name == kw::PathRoot) + { // For empty lists we need to lower the prefix so it is checked for things // like stability later. let res = self.lower_import_res(id, span); @@ -633,7 +638,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, Const::No, i.id, &itctx, |this| { + self.lower_generics(generics, Const::No, i.id, itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -650,8 +655,8 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } ForeignItemKind::Static(t, m, _) => { - let ty = self - .lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = + self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); hir::ForeignItemKind::Static(ty, *m) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -722,11 +727,11 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124) - &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy), + ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy), ); self.arena.alloc(t) } else { - self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)) + self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)) }; let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs); @@ -755,12 +760,10 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, i.id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this.lower_ty( - ty, - &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), - ); + let ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); hir::TraitItemKind::Const(ty, body) @@ -803,18 +806,18 @@ impl<'hir> LoweringContext<'_, 'hir> { &generics, Const::No, i.id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { this.lower_ty( x, - &ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), + ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), ) }); hir::TraitItemKind::Type( this.lower_param_bounds( bounds, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, ) @@ -882,10 +885,10 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, Const::No, i.id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = + this.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); let body = this.lower_const_body(i.span, expr.as_deref()); hir::ImplItemKind::Const(ty, body) @@ -916,7 +919,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &generics, Const::No, i.id, - &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { let guar = this.dcx().span_delayed_bug( @@ -929,7 +932,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(ty) => { let ty = this.lower_ty( ty, - &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true }, + ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true }, ); hir::ImplItemKind::Type(ty) } @@ -1323,7 +1326,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // synthesize a host effect param for them. We reject `const` on them during AST validation. let constness = if kind == FnDeclKind::Inherent { sig.header.constness } else { Const::No }; let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, constness, id, &itctx, |this| { + let (generics, decl) = self.lower_generics(generics, constness, id, itctx, |this| { this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) @@ -1401,7 +1404,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics: &Generics, constness: Const, parent_node_id: NodeId, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { debug_assert!(self.impl_trait_defs.is_empty()); @@ -1607,7 +1610,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds: &[GenericBound], colon_span: Option<Span>, parent_span: Span, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, origin: PredicateOrigin, ) -> Option<hir::WherePredicate<'hir>> { // Do not create a clause if we do not have anything inside it. @@ -1681,10 +1684,10 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params: self .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self - .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), bounds: self.lower_param_bounds( bounds, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), span: self.lower_span(*span), origin: PredicateOrigin::WhereClause, @@ -1695,7 +1698,7 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime: self.lower_lifetime(lifetime), bounds: self.lower_param_bounds( bounds, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), in_where_clause: true, }) @@ -1703,9 +1706,9 @@ impl<'hir> LoweringContext<'_, 'hir> { WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty: self - .lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), rhs_ty: self - .lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), span: self.lower_span(*span), }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 063b6627050..4ef9c7607be 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -36,8 +36,6 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(let_chains)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -675,7 +673,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { (None, None) }; - let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies); + let num_nodes = self.item_local_id_counter.as_usize(); + let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; @@ -1006,7 +1005,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_assoc_ty_constraint( &mut self, constraint: &AssocConstraint, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); // lower generic arguments of identifier in constraint @@ -1085,32 +1084,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TypeBindingKind::Equality { term } } AssocConstraintKind::Bound { bounds } => { - enum DesugarKind<'a> { + enum DesugarKind { ImplTrait, - Error(&'a ImplTraitPosition), + Error(ImplTraitPosition), Bound, } // Piggy-back on the `impl Trait` context to figure out the correct behavior. let desugar_kind = match itctx { - // We are in the return position: - // - // fn foo() -> impl Iterator<Item: Debug> - // - // so desugar to - // - // fn foo() -> impl Iterator<Item = impl Debug> - ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait, - - // We are in the argument position, but within a dyn type: + // in an argument, RPIT, or TAIT, if we are within a dyn type: // // fn foo(x: dyn Iterator<Item: Debug>) // - // so desugar to + // then desugar to: // // fn foo(x: dyn Iterator<Item = impl Debug>) - ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait, + // + // This is because dyn traits must have all of their associated types specified. + ImplTraitContext::ReturnPositionOpaqueTy { .. } + | ImplTraitContext::TypeAliasesOpaqueTy { .. } + | ImplTraitContext::Universal + if self.is_in_dyn_type => + { + DesugarKind::ImplTrait + } ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => { DesugarKind::Error(position) @@ -1163,7 +1160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { DesugarKind::Error(position) => { let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding { span: constraint.span, - position: DiagnosticArgFromDisplay(position), + position: DiagnosticArgFromDisplay(&position), }); let err_ty = &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar))); @@ -1210,7 +1207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_arg( &mut self, arg: &ast::GenericArg, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), @@ -1289,7 +1286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: &ImplTraitContext) -> &'hir hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { self.arena.alloc(self.lower_ty_direct(t, itctx)) } @@ -1299,7 +1296,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option<ptr::P<QSelf>>, path: &Path, param_mode: ParamMode, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::Ty<'hir> { // Check whether we should interpret this as a bare trait object. // This check mirrors the one in late resolution. We only introduce this special case in @@ -1341,7 +1338,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: &ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => { @@ -1460,13 +1457,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self .lower_opaque_impl_trait( span, - *origin, + origin, *def_node_id, bounds, - Some(*fn_kind), + Some(fn_kind), itctx, ), - &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self + ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self .lower_opaque_impl_trait( span, hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, @@ -1513,9 +1510,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .create_feature_err( MisplacedImplTrait { span: t.span, - position: DiagnosticArgFromDisplay(position), + position: DiagnosticArgFromDisplay(&position), }, - *feature, + feature, ) .emit(); hir::TyKind::Err(guar) @@ -1523,7 +1520,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(position) => { let guar = self.dcx().emit_err(MisplacedImplTrait { span: t.span, - position: DiagnosticArgFromDisplay(position), + position: DiagnosticArgFromDisplay(&position), }); hir::TyKind::Err(guar) } @@ -1581,7 +1578,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { opaque_ty_node_id: NodeId, bounds: &GenericBounds, fn_kind: Option<FnDeclKind>, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1848,7 +1845,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) } }; - self.lower_ty_direct(¶m.ty, &itctx) + self.lower_ty_direct(¶m.ty, itctx) })); let output = match coro { @@ -1876,7 +1873,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } }; - hir::FnRetTy::Return(self.lower_ty(ty, &itctx)) + hir::FnRetTy::Return(self.lower_ty(ty, itctx)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, @@ -1977,7 +1974,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output: &FnRetTy, coro: CoroutineKind, opaque_ty_span: Span, - nested_impl_trait_context: ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future<Output = T>` from the return type. let output_ty = match output { @@ -1985,7 +1982,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - self.lower_ty(ty, &nested_impl_trait_context) + self.lower_ty(ty, itctx) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -2025,7 +2022,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( @@ -2164,7 +2161,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .map(|def| { self.lower_ty( def, - &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), ) }); @@ -2174,7 +2171,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericParamKind::Const { ty, kw_span: _, default } => { let ty = self - .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); // Not only do we deny const param defaults in binders but we also map them to `None` // since later compiler stages cannot handle them (and shouldn't need to be able to). @@ -2204,7 +2201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, modifiers: ast::TraitBoundModifiers, p: &TraitRef, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::TraitRef<'hir> { let path = match self.lower_qpath( p.ref_id, @@ -2224,7 +2221,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, modifiers: ast::TraitBoundModifiers, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = @@ -2233,7 +2230,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } } - fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> { + fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } @@ -2241,7 +2238,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds( &mut self, bounds: &[GenericBound], - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> hir::GenericBounds<'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } @@ -2249,7 +2246,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bounds_mut<'s>( &'s mut self, bounds: &'s [GenericBound], - itctx: &'s ImplTraitContext, + itctx: ImplTraitContext, ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } @@ -2285,7 +2282,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, /* colon_span */ None, span, - &ImplTraitContext::Universal, + ImplTraitContext::Universal, hir::PredicateOrigin::ImplTrait, ); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 0af141ff99a..c097feb6b34 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -38,7 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); @@ -55,7 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); break hir::PatKind::Path(qpath); @@ -66,7 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 76c7e530a6b..48941a232c2 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -27,7 +27,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option<ptr::P<QSelf>>, p: &Path, param_mode: ParamMode, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, // modifiers of the impl/bound if this is a trait path modifiers: Option<ast::TraitBoundModifiers>, ) -> hir::QPath<'hir> { @@ -205,7 +205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, ParenthesizedGenericArgs::Err, - &ImplTraitContext::Disallowed(ImplTraitPosition::Path), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, None, ) @@ -220,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment: &PathSegment, param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, constness: Option<ast::BoundConstness>, // Additional features ungated with a bound modifier like `async`. // This is passed down to the implicit associated type binding in @@ -374,7 +374,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &AngleBracketedArgs, param_mode: ParamMode, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, ) -> (GenericArgsCtor<'hir>, bool) { let has_non_lt_args = data.args.iter().any(|arg| match arg { AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) @@ -405,7 +405,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_parenthesized_parameter_data( &mut self, data: &ParenthesizedArgs, - itctx: &ImplTraitContext, + itctx: ImplTraitContext, bound_modifier_allowed_features: Option<Lrc<[Symbol]>>, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this @@ -415,7 +415,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { // Only allow `impl Trait` in return position. i.e.: @@ -429,7 +429,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.lower_ty( ty, - &ImplTraitContext::FeatureGated( + ImplTraitContext::FeatureGated( ImplTraitPosition::FnTraitReturn, sym::impl_trait_in_fn_trait_return, ), @@ -437,7 +437,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } FnRetTy::Ty(ty) => { - self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) } FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 5f54a0ddf8c..9662c73ca85 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::{codes::*, AddToDiagnostic, Applicability}; +use rustc_errors::{codes::*, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessageOp}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -372,13 +372,7 @@ pub struct EmptyLabelManySpans(pub Vec<Span>); // The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each impl AddToDiagnostic for EmptyLabelManySpans { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) - where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.span_labels(self.0, ""); } } @@ -735,13 +729,7 @@ pub struct StableFeature { } impl AddToDiagnostic for StableFeature { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) - where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index fa6cdd55c3d..74d0fff2734 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -11,8 +11,6 @@ #![feature(if_let_guard)] #![feature(iter_is_partitioned)] #![feature(let_chains)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] pub mod ast_validation; mod errors; diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 61617beb86b..b9e217a21e3 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,8 +1,6 @@ #![allow(internal_features)] #![feature(rustdoc_internals)] #![doc(rust_logo)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![feature(box_patterns)] mod helpers; diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 3c5bcecddea..dd87a5c4dc3 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -8,8 +8,6 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![feature(let_chains)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 948af039537..6a683d129de 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::path_utils::allow_two_phase_borrow; use crate::place_ext::PlaceExt; use crate::BorrowIndex; diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 6cbcda37f50..429bcb74a8e 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,3 +1,6 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_errors::{codes::*, struct_span_code_err, DiagCtxt, DiagnosticBuilder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index 041ac75ec01..ff11e4db121 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,6 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use rustc_data_structures::graph::scc::Sccs; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index becfa535a59..a58fe2b7447 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! This file provides API for compiler consumers. use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 1bd891bdd68..bc5bd787956 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::WithSuccessors; use rustc_index::bit_set::BitSet; diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index d0cf339e7ba..6fd80d005d9 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_middle::mir::visit::{ MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index bb5335febbf..a540fcee871 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,6 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use rustc_errors::DiagnosticBuilder; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6debb3362b0..f87269960bc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,5 +1,8 @@ // ignore-tidy-filelength +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use either::Either; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; @@ -401,66 +404,60 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } let typeck = self.infcx.tcx.typeck(self.mir_def_id()); let hir_id = hir.parent_id(expr.hir_id); - if let Some(parent) = self.infcx.tcx.opt_hir_node(hir_id) { - let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind - && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) - { - (def_id.as_local(), args, 1) - } else if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(call, args) = parent_expr.kind - && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() - { - (def_id.as_local(), args, 0) - } else { - (None, &[][..], 0) + let parent = self.infcx.tcx.hir_node(hir_id); + let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind + && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) + { + (def_id.as_local(), args, 1) + } else if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(call, args) = parent_expr.kind + && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() + { + (def_id.as_local(), args, 0) + } else { + (None, &[][..], 0) + }; + if let Some(def_id) = def_id + && let node = + self.infcx.tcx.hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id)) + && let Some(fn_sig) = node.fn_sig() + && let Some(ident) = node.ident() + && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) + { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this parameter takes ownership of the value".to_string(), + ); + let descr = match node.fn_kind() { + Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", + Some(hir::intravisit::FnKind::Method(..)) => "method", + Some(hir::intravisit::FnKind::Closure) => "closure", }; - if let Some(def_id) = def_id - && let Some(node) = self - .infcx - .tcx - .opt_hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id)) - && let Some(fn_sig) = node.fn_sig() - && let Some(ident) = node.ident() - && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) - { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this parameter takes ownership of the value".to_string(), - ); - let descr = match node.fn_kind() { - Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", - Some(hir::intravisit::FnKind::Method(..)) => "method", - Some(hir::intravisit::FnKind::Closure) => "closure", - }; - span.push_span_label(ident.span, format!("in this {descr}")); - err.span_note( - span, - format!( - "consider changing this parameter type in {descr} `{ident}` to \ + span.push_span_label(ident.span, format!("in this {descr}")); + err.span_note( + span, + format!( + "consider changing this parameter type in {descr} `{ident}` to \ borrow instead if owning the value isn't necessary", - ), - ); - } - let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind - && let hir::ExprKind::Path(hir::QPath::LangItem( - LangItem::IntoIterIntoIter, - _, - )) = call_expr.kind - { - // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. - } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = - move_spans - { - // We already suggest cloning for these cases in `explain_captures`. - } else { - self.suggest_cloning(err, ty, expr, move_span); - } + ), + ); + } + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind + && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) = + call_expr.kind + { + // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. + } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans + { + // We already suggest cloning for these cases in `explain_captures`. + } else { + self.suggest_cloning(err, ty, expr, move_span); } } if let Some(pat) = finder.pat { @@ -1762,7 +1759,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn_decl: hir::FnDecl { inputs, .. }, .. }) = e.kind - && let Some(hir::Node::Expr(body)) = self.tcx.opt_hir_node(body.hir_id) + && let hir::Node::Expr(body) = self.tcx.hir_node(body.hir_id) { self.suggest_arg = "this: &Self".to_string(); if inputs.len() > 0 { @@ -1828,11 +1825,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - if let Some(hir::Node::ImplItem(hir::ImplItem { + if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. - })) = self.infcx.tcx.opt_hir_node(self.mir_hir_id()) - && let Some(hir::Node::Expr(expr)) = self.infcx.tcx.opt_hir_node(body_id.hir_id) + }) = self.infcx.tcx.hir_node(self.mir_hir_id()) + && let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id) { let mut finder = ExpressionFinder { capture_span: *capture_kind_span, @@ -2400,8 +2397,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let proper_span = proper_span.source_callsite(); if let Some(scope) = self.body.source_scopes.get(source_info.scope) && let ClearCrossCrate::Set(scope_data) = &scope.local_data - && let Some(node) = self.infcx.tcx.opt_hir_node(scope_data.lint_root) - && let Some(id) = node.body_id() + && let Some(id) = self.infcx.tcx.hir_node(scope_data.lint_root).body_id() && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind { for stmt in block.stmts { diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 4f66468a865..483ecee850b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,5 +1,8 @@ //! Print diagnostics to explain why values are borrowed. +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -87,7 +90,7 @@ impl<'tcx> BorrowExplanation<'tcx> { if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind && let [hir::PathSegment { ident, args: None, .. }] = p.segments && let hir::def::Res::Local(hir_id) = p.res - && let Some(hir::Node::Pat(pat)) = tcx.opt_hir_node(hir_id) + && let hir::Node::Pat(pat) = tcx.hir_node(hir_id) { err.span_label(pat.span, format!("binding `{ident}` declared here")); } diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs index 2c4d953f011..ff4f2bb9614 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -1,6 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use std::collections::BTreeSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs index 2495613fea1..94b17e0a2f9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs @@ -1,6 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use std::collections::VecDeque; use std::rc::Rc; diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 0a0bb75a2a3..126a50c91b4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,3 +1,6 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 55649ec2f16..9e7fd45ec19 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,3 +1,6 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use hir::ExprKind; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_hir as hir; @@ -396,7 +399,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_hir_id = captured_place.get_root_variable(); - if let Some(Node::Pat(pat)) = self.infcx.tcx.opt_hir_node(upvar_hir_id) + if let Node::Pat(pat) = self.infcx.tcx.hir_node(upvar_hir_id) && let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) = pat.kind { @@ -688,15 +691,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { break; } f_in_trait_opt.and_then(|f_in_trait| { - match self.infcx.tcx.opt_hir_node(f_in_trait) { - Some(Node::TraitItem(hir::TraitItem { + match self.infcx.tcx.hir_node(f_in_trait) { + Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn( hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. }, _, ), .. - })) => { + }) => { let hir::Ty { span, .. } = inputs[local.index() - 1]; Some(span) } @@ -759,10 +762,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // `let &b = a;` -> `let &(mut b) = a;` if let Some(hir_id) = hir_id - && let Some(hir::Node::Local(hir::Local { + && let hir::Node::Local(hir::Local { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. - })) = self.infcx.tcx.opt_hir_node(hir_id) + }) = self.infcx.tcx.hir_node(hir_id) && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { @@ -1206,7 +1209,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(hir_id) = hir_id - && let Some(hir::Node::Local(local)) = self.infcx.tcx.opt_hir_node(hir_id) + && let hir::Node::Local(local) = self.infcx.tcx.hir_node(hir_id) { let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap()); if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait() diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index bac1d9dd57f..93e28a5f3f3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -1,6 +1,9 @@ //! Contains utilities for generating suggestions for borrowck errors related to unsatisfied //! outlives constraints. +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_middle::ty::RegionVid; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8c8ca1ead40..e69d2ca966b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! Error reporting machinery for lifetime errors. use rustc_data_structures::fx::FxIndexSet; @@ -216,7 +214,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(id) = placeholder.bound.kind.get_id() && let Some(placeholder_id) = id.as_local() && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id) - && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics() + && let Some(generics_impl) = + hir.get_parent(hir.parent_id(gat_hir_id)).generics() { Some((gat_hir_id, generics_impl)) } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index c91b8eaab05..e008d230656 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -1,6 +1,10 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use std::fmt::{self, Display}; use std::iter; +use rustc_data_structures::fx::IndexEntry; use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -14,7 +18,7 @@ use crate::{universal_regions::DefiningTy, MirBorrowckCtxt}; /// A name for a particular region used in emitting diagnostics. This name could be a generated /// name like `'1`, a name used by the user like `'a`, or a name like `'static`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) struct RegionName { /// The name of the region (interned). pub(crate) name: Symbol, @@ -25,7 +29,7 @@ pub(crate) struct RegionName { /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that /// was named by the user would get `NamedLateParamRegion` and `'static` lifetime would get `Static`. /// This helps to print the right kinds of diagnostics. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) enum RegionNameSource { /// A bound (not free) region that was instantiated at the def site (not an HRTB). NamedEarlyParamRegion(Span), @@ -42,7 +46,7 @@ pub(crate) enum RegionNameSource { /// The region corresponding to the return type of a closure. AnonRegionFromOutput(RegionNameHighlight, &'static str), /// The region from a type yielded by a coroutine. - AnonRegionFromYieldTy(Span, String), + AnonRegionFromYieldTy(Span, Symbol), /// An anonymous region from an async fn. AnonRegionFromAsyncFn(Span), /// An anonymous region from an impl self type or trait @@ -51,7 +55,7 @@ pub(crate) enum RegionNameSource { /// Describes what to highlight to explain to the user that we're giving an anonymous region a /// synthesized name, and how to highlight it. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub(crate) enum RegionNameHighlight { /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR. MatchedHirTy(Span), @@ -59,11 +63,11 @@ pub(crate) enum RegionNameHighlight { MatchedAdtAndSegment(Span), /// The anonymous region corresponds to a region where the type annotation is completely missing /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference. - CannotMatchHirTy(Span, String), + CannotMatchHirTy(Span, Symbol), /// The anonymous region corresponds to a region where the type annotation is completely missing /// from the code, and *even if* we print out the full name of the type, the region name won't /// be included. This currently occurs for opaque types like `impl Future`. - Occluded(Span, String), + Occluded(Span, Symbol), } impl RegionName { @@ -247,25 +251,28 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { assert!(self.regioncx.universal_regions().is_universal_region(fr)); - if let Some(value) = self.region_names.try_borrow_mut().unwrap().get(&fr) { - return Some(value.clone()); - } + match self.region_names.borrow_mut().entry(fr) { + IndexEntry::Occupied(precomputed_name) => Some(*precomputed_name.get()), + IndexEntry::Vacant(slot) => { + let new_name = self + .give_name_from_error_region(fr) + .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) + .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) + .or_else(|| { + self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr) + }); + + if let Some(new_name) = new_name { + slot.insert(new_name); + } + debug!("give_region_a_name: gave name {:?}", new_name); - let value = self - .give_name_from_error_region(fr) - .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr)) - .or_else(|| self.give_name_if_anonymous_region_appears_in_arg_position_impl_trait(fr)); - - if let Some(value) = &value { - self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone()); + new_name + } } - - debug!("give_region_a_name: gave name {:?}", value); - value } /// Checks for the case where `fr` maps to something that the @@ -457,9 +464,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ); if type_name.contains(&format!("'{counter}")) { // Only add a label if we can confirm that a region was labelled. - RegionNameHighlight::CannotMatchHirTy(span, type_name) + RegionNameHighlight::CannotMatchHirTy(span, Symbol::intern(&type_name)) } else { - RegionNameHighlight::Occluded(span, type_name) + RegionNameHighlight::Occluded(span, Symbol::intern(&type_name)) } } @@ -888,7 +895,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: self.synthesize_region_name(), - source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), + source: RegionNameSource::AnonRegionFromYieldTy(yield_span, Symbol::intern(&type_name)), }) } @@ -980,7 +987,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { Some(RegionName { name: region_name, source: RegionNameSource::AnonRegionFromArgument( - RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?.to_string()), + RegionNameHighlight::CannotMatchHirTy(arg_span, arg_name?), ), }) } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 28e07f2a81e..0479cd8af35 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -1,6 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use crate::region_infer::RegionInferenceContext; use rustc_index::IndexSlice; use rustc_middle::mir::{Body, Local}; diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index c54e7070478..68dc9a6764b 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::location::{LocationIndex, LocationTable}; use crate::BorrowIndex; use polonius_engine::AllFacts as PoloniusFacts; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index bb64571889b..4dba34c11f9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -111,14 +111,16 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { let (input_body, promoted) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def)); - if input_body.borrow().should_skip() { - debug!("Skipping borrowck because of injected body"); + let input_body: &Body<'_> = &input_body.borrow(); + + if input_body.should_skip() || input_body.tainted_by_errors.is_some() { + debug!("Skipping borrowck because of injected body or tainted body"); // Let's make up a borrowck result! Fun times! let result = BorrowCheckResult { concrete_opaque_types: FxIndexMap::default(), closure_requirements: None, used_mut_upvars: SmallVec::new(), - tainted_by_errors: None, + tainted_by_errors: input_body.tainted_by_errors, }; return tcx.arena.alloc(result); } @@ -127,7 +129,6 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); - let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; debug!("mir_borrowck done"); diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs index 6f09393169f..63e59217e5d 100644 --- a/compiler/rustc_borrowck/src/location.rs +++ b/compiler/rustc_borrowck/src/location.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_index::IndexVec; use rustc_middle::mir::{BasicBlock, Body, Location}; diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index 842e9008058..5129b32d492 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_index::{IndexSlice, IndexVec}; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 7ace013975e..80d79e1beb7 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! The entry point of the NLL borrow checker. use polonius_engine::{Algorithm, Output}; @@ -184,7 +182,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( // Solve the region constraints. let (closure_region_requirements, nll_errors) = - regioncx.solve(infcx, param_env, body, polonius_output.clone()); + regioncx.solve(infcx, body, polonius_output.clone()); if !nll_errors.is_empty() { // Suppress unhelpful extra errors in `infer_opaque_types`. diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 4cfde47664e..adafad7fa2f 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; use crate::places_conflict; use crate::AccessDepth; diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs index 3d7e8c6ebf3..b59ab7fafa5 100644 --- a/compiler/rustc_borrowck/src/place_ext.rs +++ b/compiler/rustc_borrowck/src/place_ext.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::borrow_set::LocalsStateAtExit; use rustc_hir as hir; use rustc_middle::mir::ProjectionElem; diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 777ebf0d438..7e8dba43b71 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -50,8 +50,6 @@ //! and either equal or disjoint. //! - If we did run out of access, the borrow can access a part of it. -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 5c9056272cc..93aae1a7f97 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs index 5df94383702..53adad5561e 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index e9c9709bd1f..8bb3dc88b34 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an //! place are formed by stripping away fields and derefs, except that //! we stop when we reach the deref of a shared reference. [...] " diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index cfbb2766c33..53541b33c41 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! As part of generating the regions, if you enable `-Zdump-mir=nll`, //! we will generate an annotated copy of the MIR that includes the //! state of region inference. This code handles emitting the region diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 408c8390e76..c103ba3c407 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! This module provides linkage between RegionInferenceContext and //! `rustc_graphviz` traits, specialized to attaching borrowck analysis //! data to rendered labels. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 89b203f80a4..3153b709ffe 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -658,7 +658,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(super) fn solve( &mut self, infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, polonius_output: Option<Rc<PoloniusOutput>>, ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) { @@ -674,7 +673,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // eagerly. let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new); - self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer); + self.check_type_tests(infcx, outlives_requirements.as_mut(), &mut errors_buffer); debug!(?errors_buffer); debug!(?outlives_requirements); @@ -932,7 +931,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn check_type_tests( &self, infcx: &InferCtxt<'tcx>, - body: &Body<'tcx>, mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>, errors_buffer: &mut RegionErrors<'tcx>, ) { @@ -957,12 +955,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements { - if self.try_promote_type_test( - infcx, - body, - type_test, - propagated_outlives_requirements, - ) { + if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) { continue; } } @@ -1016,7 +1009,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn try_promote_type_test( &self, infcx: &InferCtxt<'tcx>, - body: &Body<'tcx>, type_test: &TypeTest<'tcx>, propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>, ) -> bool { @@ -1179,35 +1171,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty))) } - /// Returns a universally quantified region that outlives the - /// value of `r` (`r` may be existentially or universally - /// quantified). - /// - /// Since `r` is (potentially) an existential region, it has some - /// value which may include (a) any number of points in the CFG - /// and (b) any number of `end('x)` elements of universally - /// quantified regions. To convert this into a single universal - /// region we do as follows: - /// - /// - Ignore the CFG points in `'r`. All universally quantified regions - /// include the CFG anyhow. - /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding - /// a result `'y`. - #[instrument(skip(self), level = "debug", ret)] - pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!(r = %self.region_value_str(r)); - - // Find the smallest universal region that contains all other - // universal regions within `region`. - let mut lub = self.universal_regions.fr_fn_body; - let r_scc = self.constraint_sccs.scc(r); - for ur in self.scc_values.universal_regions_outlived_by(r_scc) { - lub = self.universal_region_relations.postdom_upper_bound(lub, ur); - } - - lub - } - /// Like `universal_upper_bound`, but returns an approximation more suitable /// for diagnostics. If `r` contains multiple disjoint universal regions /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 462b5c8da42..636c174e002 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -418,6 +418,8 @@ fn check_opaque_type_parameter_valid( .into_iter() .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) .collect(); + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] return Err(tcx .dcx() .struct_span_err(span, "non-defining opaque type use in defining scope") diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index fe56bd54a3f..eeb944702a7 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; use itertools::Itertools; diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index e147f62011d..b1caaa63881 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxIndexSet; use rustc_index::bit_set::SparseBitMatrix; diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index a31d39e14cd..dca8df32800 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use crate::BorrowckInferCtxt; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fd20d352203..cfb46f3ac8a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] //! This pass type-checks the MIR to ensure it is not broken. use std::rc::Rc; @@ -213,7 +211,6 @@ pub(crate) fn type_check<'mir, 'tcx>( CustomTypeOp::new( |ocx| { ocx.infcx.register_member_constraints( - param_env, opaque_type_key, decl.hidden_type.ty, decl.hidden_type.span, @@ -1984,6 +1981,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::SizedBound, ); } + &Rvalue::NullaryOp(NullOp::DebugAssertions, _) => {} Rvalue::ShallowInitBox(operand, ty) => { self.check_operand(operand, location); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 111eaaf60f7..a7bdfa4eae7 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -12,6 +12,9 @@ //! The code in this file doesn't *do anything* with those results; it //! just returns them for other code to use. +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_data_structures::fx::FxHashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs index 6ac8e1ba715..81757a62e5b 100644 --- a/compiler/rustc_borrowck/src/used_muts.rs +++ b/compiler/rustc_borrowck/src/used_muts.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxIndexSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index eadb48ddd36..8d2e06bf30d 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, - Level, MultiSpan, SingleLabelManySpans, + codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, + IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -611,13 +611,7 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl AddToDiagnostic for FormatUnusedArg { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F) - where - F: Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { diag.arg("named", self.named); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); diag.span_label(self.span, msg); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4d7957ef4dd..d30ccab2394 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -2,6 +2,8 @@ //! injecting code into the crate before it is lowered to HIR. #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(rustdoc_internals)] #![doc(rust_logo)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 0afd6d0e670..a7e76fbc128 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -767,6 +767,15 @@ fn codegen_stmt<'tcx>( NullOp::OffsetOf(fields) => { layout.offset_of_subfield(fx, fields.iter()).bytes() } + NullOp::DebugAssertions => { + let val = fx.tcx.sess.opts.debug_assertions; + let val = CValue::by_val( + fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()), + fx.layout_of(fx.tcx.types.bool), + ); + lval.write_cvalue(fx, val); + return; + } }; let val = CValue::by_val( fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()), diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 416f87fcc87..7c432e9c590 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -3,6 +3,8 @@ #![cfg_attr(doc, doc(rust_logo))] #![feature(rustc_private)] // Note: please avoid adding other feature gates where possible +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f8f054db65e..863b6333bcc 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -27,8 +27,6 @@ #![recursion_limit="256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] extern crate rustc_apfloat; extern crate rustc_ast; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 76c9ac6614a..f961cd2d00b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -461,6 +461,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D } ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id), ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), + ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id), ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id), ty::Adt(def, ..) => match def.adt_kind() { AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id), @@ -1068,6 +1069,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>( let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() { ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()), ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()), + ty::CoroutineClosure(def_id, args) => (def_id, args.as_coroutine_closure().upvar_tys()), _ => { bug!( "build_upvar_field_di_nodes() called with non-closure-or-coroutine-type: {:?}", @@ -1153,7 +1155,8 @@ fn build_closure_env_di_node<'ll, 'tcx>( unique_type_id: UniqueTypeId<'tcx>, ) -> DINodeCreationResult<'ll> { let closure_env_type = unique_type_id.expect_ty(); - let &ty::Closure(def_id, _args) = closure_env_type.kind() else { + let &(ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _)) = closure_env_type.kind() + else { bug!("build_closure_env_di_node() called with non-closure-type: {:?}", closure_env_type) }; let containing_scope = get_namespace_for_item(cx, def_id); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b4512af38e3..e3e48ecb3aa 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1985,10 +1985,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( match in_elem.kind() { ty::RawPtr(p) => { - let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - assert!(!check_sized); // we are in codegen, so we shouldn't see these types require!( metadata.is_unit(), InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem } @@ -2000,10 +1999,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } match out_elem.kind() { ty::RawPtr(p) => { - let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| { bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) }); - assert!(!check_sized); // we are in codegen, so we shouldn't see these types require!( metadata.is_unit(), InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f4f29078190..de96bf477ad 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -15,8 +15,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(impl_trait_in_assoc_type)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 7d2f5bb193a..c4aaf421444 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -9,7 +9,7 @@ ar_archive_writer = "0.1.5" bitflags = "2.4.1" cc = "1.0.69" itertools = "0.11" -jobserver = "0.1.27" +jobserver = "0.1.28" pathdiff = "0.2.0" regex = "1.4" rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index fc833a3863e..1afc597a7ef 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,6 +2,8 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(if_let_guard)] diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 266505d3f26..5c6060a7159 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -672,17 +672,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match null_op { mir::NullOp::SizeOf => { assert!(bx.cx().type_is_sized(ty)); - layout.size.bytes() + let val = layout.size.bytes(); + bx.cx().const_usize(val) } mir::NullOp::AlignOf => { assert!(bx.cx().type_is_sized(ty)); - layout.align.abi.bytes() + let val = layout.align.abi.bytes(); + bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(bx.cx(), fields.iter()).bytes() + let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes(); + bx.cx().const_usize(val) + } + mir::NullOp::DebugAssertions => { + let val = bx.tcx().sess.opts.debug_assertions; + bx.cx().const_bool(val) } }; - let val = bx.cx().const_usize(val); let tcx = self.cx.tcx(); OperandRef { val: OperandValue::Immediate(val), diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index a158fc6e260..ac7dfbb261d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,5 +1,6 @@ use rustc_middle::mir; use rustc_middle::mir::NonDivergingIntrinsic; +use rustc_session::config::OptLevel; use super::FunctionCx; use super::LocalRef; @@ -67,8 +68,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_coverage(bx, coverage, statement.source_info.scope); } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { - let op_val = self.codegen_operand(bx, op); - bx.assume(op_val.immediate()); + if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) { + let op_val = self.codegen_operand(bx, op); + bx.assume(op_val.immediate()); + } } mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( mir::CopyNonOverlapping { ref count, ref src, ref dst }, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d48329b6c69..f0f1008aba8 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -246,13 +246,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); } let val = match null_op { - mir::NullOp::SizeOf => layout.size.bytes(), - mir::NullOp::AlignOf => layout.align.abi.bytes(), + mir::NullOp::SizeOf => { + let val = layout.size.bytes(); + Scalar::from_target_usize(val, self) + } + mir::NullOp::AlignOf => { + let val = layout.align.abi.bytes(); + Scalar::from_target_usize(val, self) + } mir::NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(self, fields.iter()).bytes() + let val = layout.offset_of_subfield(self, fields.iter()).bytes(); + Scalar::from_target_usize(val, self) + } + mir::NullOp::DebugAssertions => { + // The checks hidden behind this are always better done by the interpreter + // itself, because it knows the runtime state better. + Scalar::from_bool(false) } }; - self.write_scalar(Scalar::from_target_usize(val, self), &dest)?; + self.write_scalar(val, &dest)?; } ShallowInitBox(ref operand, _) => { diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 85a2e4778d2..ff20fc5092c 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -377,12 +377,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // to fields, which can yield non-normalized types. So we need to provide a // normalization function. let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); - let (meta, only_if_sized) = ty.ptr_metadata_ty(*self.tcx, normalize); - assert!( - !only_if_sized, - "there should be no more 'maybe has that metadata' types during interpretation" - ); - meta + ty.ptr_metadata_ty(*self.tcx, normalize) }; return Ok(meta_ty(caller) == meta_ty(callee)); } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 946a49982aa..839cfd8d85a 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -5,9 +5,9 @@ Rust MIR: a lowered representation of Rust. */ #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] #![feature(rustdoc_internals)] #![doc(rust_logo)] -#![deny(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 5ff81615552..ee3f349c6b8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -544,7 +544,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {} + Rvalue::NullaryOp( + NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::DebugAssertions, + _, + ) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, operand) => { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index c4542aaa7b2..5ce6a71c4bd 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -60,6 +60,8 @@ impl<'tcx> MirPass<'tcx> for Validator { ty::Closure(..) => Abi::RustCall, ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, + // No need to do MIR validation on error bodies + ty::Error(_) => return, _ => { span_bug!(body.span, "unexpected body ty: {:?} phase {:?}", body_ty, mir_phase) } @@ -1139,7 +1141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::AddressOf(_, _) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::DebugAssertions, _) | Rvalue::Discriminant(_) => {} } self.super_rvalue(rvalue, location); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 08aa68ca54a..0635d8552ae 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -11,7 +11,7 @@ either = "1.0" elsa = "=1.7.1" ena = "0.14.2" indexmap = { version = "2.0.0" } -jobserver_crate = { version = "0.1.27", package = "jobserver" } +jobserver_crate = { version = "0.1.28", package = "jobserver" } libc = "0.2" measureme = "11" rustc-hash = "1.1.0" diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 412e33aaa65..89088bc5c1b 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -23,7 +23,10 @@ static GLOBAL_CLIENT: LazyLock<Result<Client, String>> = LazyLock::new(|| { if matches!( error.kind(), - FromEnvErrorKind::NoEnvVar | FromEnvErrorKind::NoJobserver | FromEnvErrorKind::Unsupported + FromEnvErrorKind::NoEnvVar + | FromEnvErrorKind::NoJobserver + | FromEnvErrorKind::NegativeFd + | FromEnvErrorKind::Unsupported ) { return Ok(default_client()); } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index a71d012db2d..2b799d6f5d3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,8 +11,6 @@ #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] #![cfg_attr(not(parallel_compiler), feature(cell_leak))] -#![deny(rustc::diagnostic_outside_of_impl)] -#![deny(rustc::untranslatable_diagnostic)] #![deny(unsafe_op_in_unsafe_fn)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 519bde98820..60f11b1bdd4 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -12,8 +12,6 @@ #![feature(let_chains)] #![feature(panic_update_hook)] #![feature(result_flattening)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 5b2766618fc..da688e385aa 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -5,8 +5,6 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![deny(rustdoc::invalid_codeblock_attributes)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] // This higher-order macro defines the error codes that are in use. It is used // in the `rustc_errors` crate. Removed error codes are listed in the comment diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index d212e18b4cd..e174cba7813 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -3,8 +3,6 @@ #![feature(lazy_cell)] #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 1763c355069..03717a4d654 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -77,11 +77,12 @@ where /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used /// (to optionally perform eager translation). - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage; + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F); } +pub trait SubdiagnosticMessageOp = + Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage; + /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. #[rustc_diagnostic_item = "DecorateLint"] diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 15effd3cbec..e936ebc7185 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -2,7 +2,7 @@ use crate::diagnostic::DiagnosticLocation; use crate::{fluent_generated as fluent, AddToDiagnostic}; use crate::{ DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, EmissionGuarantee, ErrCode, IntoDiagnostic, - IntoDiagnosticArg, Level, + IntoDiagnosticArg, Level, SubdiagnosticMessageOp, }; use rustc_ast as ast; use rustc_ast_pretty::pprust; @@ -299,7 +299,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl AddToDiagnostic for SingleLabelManySpans { - fn add_to_diagnostic_with<F>(self, diag: &mut crate::Diagnostic, _: F) { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut crate::Diagnostic, _: F) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ec5029e505f..7216fa8f5e4 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -5,6 +5,8 @@ // tidy-alphabetical-start #![allow(incomplete_features)] #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -19,6 +21,7 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] // tidy-alphabetical-end @@ -35,6 +38,7 @@ pub use codes::*; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName, DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic, + SubdiagnosticMessageOp, }; pub use diagnostic_builder::{ BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic, @@ -429,6 +433,10 @@ struct DiagCtxtInner { /// The number of non-lint errors that have been emitted, including duplicates. err_count: usize, + /// The number of stashed errors. Unlike the other counts, this can go up + /// and down, so it doesn't guarantee anything. + stashed_err_count: usize, + /// The error count shown to the user at the end. deduplicated_err_count: usize, /// The warning count shown to the user at the end. @@ -598,6 +606,7 @@ impl DiagCtxt { flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() }, lint_err_count: 0, err_count: 0, + stashed_err_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, has_printed: false, @@ -654,6 +663,7 @@ impl DiagCtxt { let mut inner = self.inner.borrow_mut(); inner.lint_err_count = 0; inner.err_count = 0; + inner.stashed_err_count = 0; inner.deduplicated_err_count = 0; inner.deduplicated_warn_count = 0; inner.has_printed = false; @@ -675,10 +685,8 @@ impl DiagCtxt { let key = (span.with_parent(None), key); if diag.is_error() { - if diag.is_lint.is_some() { - inner.lint_err_count += 1; - } else { - inner.err_count += 1; + if diag.is_lint.is_none() { + inner.stashed_err_count += 1; } } @@ -694,10 +702,8 @@ impl DiagCtxt { let key = (span.with_parent(None), key); let diag = inner.stashed_diagnostics.remove(&key)?; if diag.is_error() { - if diag.is_lint.is_some() { - inner.lint_err_count -= 1; - } else { - inner.err_count -= 1; + if diag.is_lint.is_none() { + inner.stashed_err_count -= 1; } } Some(DiagnosticBuilder::new_diagnostic(self, diag)) @@ -845,6 +851,7 @@ impl DiagCtxt { self.struct_span_warn(span, msg).emit() } + #[track_caller] pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! { self.struct_span_bug(span, msg).emit() } @@ -922,13 +929,22 @@ impl DiagCtxt { self.struct_bug(msg).emit() } - /// This excludes lint errors and delayed bugs. + /// This excludes lint errors, delayed bugs, and stashed errors. #[inline] pub fn err_count(&self) -> usize { self.inner.borrow().err_count } - /// This excludes lint errors and delayed bugs. + /// This excludes normal errors, lint errors and delayed bugs. Unless + /// absolutely necessary, avoid using this. It's dubious because stashed + /// errors can later be cancelled, so the presence of a stashed error at + /// some point of time doesn't guarantee anything -- there are no + /// `ErrorGuaranteed`s here. + pub fn stashed_err_count(&self) -> usize { + self.inner.borrow().stashed_err_count + } + + /// This excludes lint errors, delayed bugs, and stashed errors. pub fn has_errors(&self) -> Option<ErrorGuaranteed> { self.inner.borrow().has_errors().then(|| { // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. @@ -937,8 +953,8 @@ impl DiagCtxt { }) } - /// This excludes delayed bugs. Unless absolutely necessary, prefer - /// `has_errors` to this method. + /// This excludes delayed bugs and stashed errors. Unless absolutely + /// necessary, prefer `has_errors` to this method. pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> { let inner = self.inner.borrow(); let result = inner.has_errors() || inner.lint_err_count > 0; @@ -949,8 +965,8 @@ impl DiagCtxt { }) } - /// Unless absolutely necessary, prefer `has_errors` or - /// `has_errors_or_lint_errors` to this method. + /// This excludes stashed errors. Unless absolutely necessary, prefer + /// `has_errors` or `has_errors_or_lint_errors` to this method. pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> { let inner = self.inner.borrow(); let result = @@ -1224,10 +1240,8 @@ impl DiagCtxtInner { for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { - if diag.is_lint.is_some() { - self.lint_err_count -= 1; - } else { - self.err_count -= 1; + if diag.is_lint.is_none() { + self.stashed_err_count -= 1; } } else { // Unless they're forced, don't flush stashed warnings when diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 657e19277a7..cfeb31fc4c8 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] - use crate::base::ast::NestedMetaItem; use crate::errors; use crate::expand::{self, AstFragment, Invocation}; diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 2cf6a8df7c5..4da86d77dc8 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -10,7 +10,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_span)] #![feature(try_blocks)] -#![deny(rustc::untranslatable_diagnostic)] +#![allow(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 1155366db85..18f6ae35054 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -77,7 +77,7 @@ declare_features! ( /// Allows empty structs and enum variants with braces. (accepted, braced_empty_structs, "1.8.0", Some(29720)), /// Allows `c"foo"` literals. - (accepted, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723)), + (accepted, c_str_literals, "1.77.0", Some(105723)), /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. (accepted, cfg_attr_multi, "1.33.0", Some(54881)), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index cd1d9b13daa..f1c8f2e2dde 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -15,8 +15,6 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![feature(lazy_cell)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] mod accepted; mod builtin_attrs; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 040892df4c3..008c59e1be3 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -33,7 +33,7 @@ declare_features! ( // ------------------------------------------------------------------------- /// Allows using the `amdgpu-kernel` ABI. - (removed, abi_amdgpu_kernel, "CURRENT_RUSTC_VERSION", Some(51575), None), + (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None), (removed, advanced_slice_patterns, "1.0.0", Some(62254), Some("merged into `#![feature(slice_patterns)]`")), (removed, allocator, "1.0.0", None, None), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1fb91ff8bbc..42fc24c937b 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -356,7 +356,7 @@ declare_features! ( /// Allows `#[track_caller]` on async functions. (unstable, async_fn_track_caller, "1.73.0", Some(110011)), /// Allows `for await` loops. - (unstable, async_for_loop, "CURRENT_RUSTC_VERSION", Some(118898)), + (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows builtin # foo() syntax (unstable, builtin_syntax, "1.71.0", Some(110680)), /// Treat `extern "C"` function as nounwind. @@ -370,7 +370,7 @@ declare_features! ( /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (unstable, cfg_sanitize, "1.41.0", Some(39699)), /// Allows `cfg(sanitizer_cfi_generalize_pointers)` and `cfg(sanitizer_cfi_normalize_integers)`. - (unstable, cfg_sanitizer_cfi, "CURRENT_RUSTC_VERSION", Some(89653)), + (unstable, cfg_sanitizer_cfi, "1.77.0", Some(89653)), /// Allows `cfg(target_abi = "...")`. (unstable, cfg_target_abi, "1.55.0", Some(80970)), /// Allows `cfg(target(abi = "..."))`. @@ -514,7 +514,7 @@ declare_features! ( (unstable, marker_trait_attr, "1.30.0", Some(29864)), /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are /// unambiguously sound. - (incomplete, min_exhaustive_patterns, "CURRENT_RUSTC_VERSION", Some(119612)), + (incomplete, min_exhaustive_patterns, "1.77.0", Some(119612)), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. @@ -550,7 +550,7 @@ declare_features! ( /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using multiple nested field accesses in offset_of! - (unstable, offset_of_nested, "CURRENT_RUSTC_VERSION", Some(120140)), + (unstable, offset_of_nested, "1.77.0", Some(120140)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows macro attributes on expressions, statements and non-inline modules. diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index fc65d1eb8c4..e3784409af8 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -4,8 +4,6 @@ #![feature(rustdoc_internals)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(rustc::default_hash_types)] use proc_macro::TokenStream; diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 81d63338145..3359fef8c1c 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,6 +1,4 @@ #![feature(absolute_path)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use std::ffi::CString; use std::fs; diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index eba3215d931..43bee5c4be0 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -276,8 +276,6 @@ #![feature(rustdoc_internals)] #![doc(rust_logo)] #![allow(internal_features)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use LabelText::*; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ff50086ff8f..abf7a695fd2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -163,10 +163,6 @@ impl Lifetime { (LifetimeSuggestionPosition::Normal, self.ident.span) } } - - pub fn is_static(&self) -> bool { - self.res == LifetimeName::Static - } } /// A `Path` is essentially Rust's notion of a name; for instance, @@ -835,7 +831,7 @@ pub struct OwnerNodes<'tcx> { // The zeroth node's parent should never be accessed: the owner's parent is computed by the // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally // used. - pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, + pub nodes: IndexVec<ItemLocalId, ParentedNode<'tcx>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, } @@ -843,9 +839,8 @@ pub struct OwnerNodes<'tcx> { impl<'tcx> OwnerNodes<'tcx> { pub fn node(&self) -> OwnerNode<'tcx> { use rustc_index::Idx; - let node = self.nodes[ItemLocalId::new(0)].as_ref().unwrap().node; - let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode. - node + // Indexing must ensure it is an OwnerNode. + self.nodes[ItemLocalId::new(0)].node.as_owner().unwrap() } } @@ -860,9 +855,7 @@ impl fmt::Debug for OwnerNodes<'_> { .nodes .iter_enumerated() .map(|(id, parented_node)| { - let parented_node = parented_node.as_ref().map(|node| node.parent); - - debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})")) + debug_fn(move |f| write!(f, "({id:?}, {:?})", parented_node.parent)) }) .collect::<Vec<_>>(), ) @@ -3351,13 +3344,15 @@ impl<'hir> OwnerNode<'hir> { } } - pub fn span(&self) -> Span { + // Span by reference to pass to `Node::Err`. + #[allow(rustc::pass_by_value)] + pub fn span(&self) -> &'hir Span { match self { OwnerNode::Item(Item { span, .. }) | OwnerNode::ForeignItem(ForeignItem { span, .. }) | OwnerNode::ImplItem(ImplItem { span, .. }) - | OwnerNode::TraitItem(TraitItem { span, .. }) => *span, - OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => *inner_span, + | OwnerNode::TraitItem(TraitItem { span, .. }) => span, + OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => inner_span, } } @@ -3486,17 +3481,19 @@ pub enum Node<'hir> { Arm(&'hir Arm<'hir>), Block(&'hir Block<'hir>), Local(&'hir Local<'hir>), - /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants /// with synthesized constructors. Ctor(&'hir VariantData<'hir>), - Lifetime(&'hir Lifetime), GenericParam(&'hir GenericParam<'hir>), - Crate(&'hir Mod<'hir>), - Infer(&'hir InferArg), + WhereBoundPredicate(&'hir WhereBoundPredicate<'hir>), + // FIXME: Merge into `Node::Infer`. + ArrayLenInfer(&'hir InferArg), + // Span by reference to minimize `Node`'s size + #[allow(rustc::pass_by_value)] + Err(&'hir Span), } impl<'hir> Node<'hir> { @@ -3541,7 +3538,10 @@ impl<'hir> Node<'hir> { | Node::Crate(..) | Node::Ty(..) | Node::TraitRef(..) - | Node::Infer(..) => None, + | Node::Infer(..) + | Node::WhereBoundPredicate(..) + | Node::ArrayLenInfer(..) + | Node::Err(..) => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 27c834d848f..52e1109ff92 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -108,8 +108,8 @@ impl<'a> FnKind<'a> { /// An abstract representation of the HIR `rustc_middle::hir::map::Map`. pub trait Map<'hir> { - /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. - fn find(&self, hir_id: HirId) -> Option<Node<'hir>>; + /// Retrieves the `Node` corresponding to `id`. + fn hir_node(&self, hir_id: HirId) -> Node<'hir>; fn body(&self, id: BodyId) -> &'hir Body<'hir>; fn item(&self, id: ItemId) -> &'hir Item<'hir>; fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>; @@ -119,7 +119,7 @@ pub trait Map<'hir> { // Used when no map is actually available, forcing manual implementation of nested visitors. impl<'hir> Map<'hir> for ! { - fn find(&self, _: HirId) -> Option<Node<'hir>> { + fn hir_node(&self, _: HirId) -> Node<'hir> { *self; } fn body(&self, _: BodyId) -> &'hir Body<'hir> { @@ -669,6 +669,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<' pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { match len { + // FIXME: Use `visit_infer` here. ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id), ArrayLen::Body(c) => visitor.visit_anon_const(c), } diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 6c64d802e68..aff946ac580 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -9,8 +9,6 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 54d0fb6ffab..d6f604c180b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -33,10 +33,6 @@ hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the as hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes -hir_analysis_async_trait_impl_should_be_async = - method `{$method_name}` should be async because the method from the trait is async - .trait_item_label = required because the trait method is async - hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` .label = deref recursion limit reached .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) @@ -210,6 +206,9 @@ hir_analysis_manual_implementation = .label = manual implementations of `{$trait_name}` are experimental .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable +hir_analysis_method_should_return_future = method should be `async` or return a future, but it is synchronous + .note = this method is `async` so it expects a future to be returned + hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}` .label = missing one of `{$missing_items_msg}` in implementation .note = required because of this annotation diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index e37119e7d4d..1ae267d1a40 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -243,9 +243,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { speculative: bool, dup_bindings: &mut FxHashMap<DefId, Span>, path_span: Span, - constness: ty::BoundConstness, only_self_bounds: OnlySelfBounds, - polarity: ty::ImplPolarity, ) -> Result<(), ErrorGuaranteed> { // Given something like `U: SomeTrait<T = X>`, we want to produce a // predicate like `<U as SomeTrait>::T = X`. This is somewhat diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 30b10446afc..aa826c1f268 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; -use rustc_span::{symbol::kw, Span}; +use rustc_span::symbol::kw; use smallvec::SmallVec; /// Report an error that a generic argument did not match the generic parameter that was @@ -404,7 +404,6 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>( /// Used specifically for function calls. pub fn check_generic_arg_count_for_call( tcx: TyCtxt<'_>, - span: Span, def_id: DefId, generics: &ty::Generics, seg: &hir::PathSegment<'_>, @@ -418,17 +417,7 @@ pub fn check_generic_arg_count_for_call( }; let has_self = generics.parent.is_none() && generics.has_self; - check_generic_arg_count( - tcx, - span, - def_id, - seg, - generics, - gen_args, - gen_pos, - has_self, - seg.infer_args, - ) + check_generic_arg_count(tcx, def_id, seg, generics, gen_args, gen_pos, has_self, seg.infer_args) } /// Checks that the correct number of generic arguments have been provided. @@ -436,7 +425,6 @@ pub fn check_generic_arg_count_for_call( #[instrument(skip(tcx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( tcx: TyCtxt<'_>, - span: Span, def_id: DefId, seg: &hir::PathSegment<'_>, gen_params: &ty::Generics, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index cfd38fb48f4..d438d3e7c60 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -12,7 +12,7 @@ use crate::astconv::errors::prohibit_assoc_ty_binding; use crate::astconv::generics::{check_generic_arg_count, create_args_for_parent_generic_args}; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::{AmbiguousLifetimeBound, TypeofReservedKeywordUsed}; +use crate::errors::AmbiguousLifetimeBound; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; @@ -25,13 +25,13 @@ use rustc_hir as hir; 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_hir::{GenericArg, GenericArgs}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, IsSuggestable, ParamEnv, Ty, - TyCtxt, TypeVisitableExt, + self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, + TypeVisitableExt, }; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; @@ -379,7 +379,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut arg_count = check_generic_arg_count( tcx, - span, def_id, seg, generics, @@ -773,9 +772,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { speculative, &mut dup_bindings, binding.span, - constness, only_self_bounds, - polarity, ); // Okay to ignore `Err` because of `ErrorGuaranteed` (see above). } @@ -2493,7 +2490,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opaque_ty = tcx.hir().item(item_id); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => { + hir::ItemKind::OpaqueTy(&hir::OpaqueTy { .. }) => { let local_def_id = item_id.owner_id.def_id; // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as @@ -2503,7 +2500,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { local_def_id.to_def_id() }; - self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait) + self.impl_trait_ty_to_ty(def_id, lifetimes, in_trait) } ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } @@ -2539,21 +2536,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length) } - hir::TyKind::Typeof(e) => { - let ty_erased = tcx.type_of(e.def_id).instantiate_identity(); - let ty = tcx.fold_regions(ty_erased, |r, _| { - if r.is_erased() { tcx.lifetimes.re_static } else { r } - }); - let span = ast_ty.span; - let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) { - (ty, Some((span, Applicability::MachineApplicable))) - } else { - (ty, None) - }; - tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg }); - - ty - } + hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(), hir::TyKind::Infer => { // Infer also appears as the type of arguments or return // values in an ExprKind::Closure, or as @@ -2573,7 +2556,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, def_id: DefId, lifetimes: &[hir::GenericArg<'_>], - origin: OpaqueTyOrigin, in_trait: bool, ) -> Ty<'tcx> { debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d0683686d38..6edd68f1bae 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,5 +1,5 @@ use super::potentially_plural_count; -use crate::errors::LifetimesOrBoundsMismatchOnTrait; +use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture}; use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; @@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::util; +use rustc_infer::traits::{util, FulfillmentError}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -74,7 +74,6 @@ fn check_method_is_structurally_compatible<'tcx>( compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?; compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?; compare_synthetic_generics(tcx, impl_m, trait_m, delay)?; - compare_asyncness(tcx, impl_m, trait_m, delay)?; check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?; Ok(()) } @@ -414,36 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { } } -fn compare_asyncness<'tcx>( - tcx: TyCtxt<'tcx>, - impl_m: ty::AssocItem, - trait_m: ty::AssocItem, - delay: bool, -) -> Result<(), ErrorGuaranteed> { - if tcx.asyncness(trait_m.def_id).is_async() { - match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() { - ty::Alias(ty::Opaque, ..) => { - // allow both `async fn foo()` and `fn foo() -> impl Future` - } - ty::Error(_) => { - // We don't know if it's ok, but at least it's already an error. - } - _ => { - return Err(tcx - .dcx() - .create_err(crate::errors::AsyncTraitImplShouldBeAsync { - span: tcx.def_span(impl_m.def_id), - method_name: trait_m.name, - trait_item_span: tcx.hir().span_if_local(trait_m.def_id), - }) - .emit_unless(delay)); - } - }; - } - - Ok(()) -} - /// Given a method def-id in an impl, compare the method signature of the impl /// against the trait that it's implementing. In doing so, infer the hidden types /// that this method's signature provides to satisfy each return-position `impl Trait` @@ -695,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // RPITs. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(errors); - return Err(reported); + if let Err(guar) = try_report_async_mismatch(tcx, infcx, &errors, trait_m, impl_m, impl_sig) + { + return Err(guar); + } + + let guar = infcx.err_ctxt().report_fulfillment_errors(errors); + return Err(guar); } // Finally, resolve all regions. This catches wily misuses of @@ -2252,3 +2226,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { ty::AssocKind::Type => "type", } } + +/// Manually check here that `async fn foo()` wasn't matched against `fn foo()`, +/// and extract a better error if so. +fn try_report_async_mismatch<'tcx>( + tcx: TyCtxt<'tcx>, + infcx: &InferCtxt<'tcx>, + errors: &[FulfillmentError<'tcx>], + trait_m: ty::AssocItem, + impl_m: ty::AssocItem, + impl_sig: ty::FnSig<'tcx>, +) -> Result<(), ErrorGuaranteed> { + if !tcx.asyncness(trait_m.def_id).is_async() { + return Ok(()); + } + + let ty::Alias(ty::Projection, ty::AliasTy { def_id: async_future_def_id, .. }) = + *tcx.fn_sig(trait_m.def_id).skip_binder().skip_binder().output().kind() + else { + bug!("expected `async fn` to return an RPITIT"); + }; + + for error in errors { + if let traits::BindingObligation(def_id, _) = *error.root_obligation.cause.code() + && def_id == async_future_def_id + && let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred() + && let Some(proj) = proj.no_bound_vars() + && infcx.can_eq( + error.root_obligation.param_env, + proj.term.ty().unwrap(), + impl_sig.output(), + ) + { + // FIXME: We should suggest making the fn `async`, but extracting + // the right span is a bit difficult. + return Err(tcx.sess.dcx().emit_err(MethodShouldReturnFuture { + span: tcx.def_span(impl_m.def_id), + method_name: trait_m.name, + trait_item_span: tcx.hir().span_if_local(trait_m.def_id), + })); + } + } + + Ok(()) +} diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 649ac6c5aeb..3d803258c8e 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -43,8 +43,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); - match tcx.opt_hir_node(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { + match tcx.hir_node(hir_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => { generics.params.is_empty().not().then_some(generics.span) } _ => { @@ -58,8 +58,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); - match tcx.opt_hir_node(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { + match tcx.hir_node(hir_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => { Some(generics.where_clause_span) } _ => { @@ -80,8 +80,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { return None; } let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); - match tcx.opt_hir_node(hir_id) { - Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => { + match tcx.hir_node(hir_id) { + Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. }) => { Some(fn_sig.decl.output.span()) } _ => { @@ -202,7 +202,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { let start_t = tcx.type_of(start_def_id).instantiate_identity(); match start_t.kind() { ty::FnDef(..) => { - if let Some(Node::Item(it)) = tcx.opt_hir_node(start_id) { + if let Node::Item(it) = tcx.hir_node(start_id) { if let hir::ItemKind::Fn(sig, generics, _) = &it.kind { let mut error = false; if !generics.params.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 2d0d6611444..96b0cffc8a3 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -112,7 +112,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir | sym::forget | sym::black_box | sym::variant_count - | sym::ptr_mask => hir::Unsafety::Normal, + | sym::ptr_mask + | sym::debug_assertions => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, }; @@ -461,6 +462,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize) } + sym::debug_assertions => (0, Vec::new(), tcx.types.bool), + other => { tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 5cdcc1bb860..20a7663f864 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; +use crate::errors::TypeofReservedKeywordUsed; + use super::bad_placeholder; use super::ItemCtxt; pub use opaque::test_opaque_hidden_types; @@ -39,8 +41,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { { return tcx.types.usize; } - Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { - return tcx.typeck(def_id).node_type(e.hir_id); + Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => { + let ty = tcx.typeck(def_id).node_type(e.hir_id); + let ty = tcx.fold_regions(ty, |r, _| { + if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r } + }); + let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) { + (ty, Some((span, Applicability::MachineApplicable))) + } else { + (ty, None) + }; + tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg }); + return ty; } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) @@ -509,6 +521,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty x => bug!("unexpected non-type Node::GenericParam: {:?}", x), }, + Node::ArrayLenInfer(_) => tcx.types.usize, + x => { bug!("unexpected sort of node in type_of(): {:?}", x); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 4eba31e327f..bec53693d6c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -167,17 +167,6 @@ pub struct LifetimesOrBoundsMismatchOnTrait { } #[derive(Diagnostic)] -#[diag(hir_analysis_async_trait_impl_should_be_async)] -pub struct AsyncTraitImplShouldBeAsync { - #[primary_span] - // #[label] - pub span: Span, - #[label(hir_analysis_trait_item_label)] - pub trait_item_span: Option<Span>, - pub method_name: Symbol, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)] pub struct DropImplOnWrongItem { #[primary_span] @@ -1513,6 +1502,16 @@ pub struct NotSupportedDelegation<'a> { } #[derive(Diagnostic)] +#[diag(hir_analysis_method_should_return_future)] +pub struct MethodShouldReturnFuture { + #[primary_span] + pub span: Span, + pub method_name: Symbol, + #[note] + pub trait_item_span: Option<Span>, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_unused_generic_parameter)] pub(crate) struct UnusedGenericParameter { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 2e85da98269..883d416ecd1 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -55,7 +55,9 @@ This API is completely unstable and subject to change. */ +#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] +#![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] @@ -209,7 +211,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { tcx.ensure().check_unused_traits(()); - if let Some(reported) = tcx.dcx().has_errors() { Err(reported) } else { Ok(()) } + Ok(()) } /// A quasi-deprecated helper used in rustdoc and clippy to get diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 501915d2e7e..3b1ee2975fd 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -771,8 +771,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) - && let Some(parent_node) = self.tcx.opt_hir_node(parent_node) - && let hir::Node::Expr(expr) = parent_node + && let hir::Node::Expr(expr) = self.tcx.hir_node(parent_node) { match &expr.kind { hir::ExprKind::Path(qpath) => self diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9d0c5cb0f32..b90fa03a3dc 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2,8 +2,6 @@ //! the definitions in this file have equivalents in `rustc_ast_pretty`. #![recursion_limit = "256"] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] use rustc_ast as ast; use rustc_ast::util::parser::{self, AssocOp, Fixity}; @@ -23,7 +21,7 @@ use std::cell::Cell; use std::vec; pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: hir::HirId) -> String { - to_string(&map, |s| s.print_node(map.find(hir_id).unwrap())) + to_string(&map, |s| s.print_node(map.hir_node(hir_id))) } pub enum AnnNode<'a> { @@ -117,6 +115,13 @@ impl<'a> State<'a> { Node::Ctor(..) => panic!("cannot print isolated Ctor"), Node::Local(a) => self.print_local_decl(a), Node::Crate(..) => panic!("cannot print Crate"), + Node::WhereBoundPredicate(pred) => { + self.print_formal_generic_params(pred.bound_generic_params); + self.print_type(pred.bounded_ty); + self.print_bounds(":", pred.bounds); + } + Node::ArrayLenInfer(_) => self.word("_"), + Node::Err(_) => self.word("/*ERROR*/"), } } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9217c2db360..299ee092a80 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -261,23 +261,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjusted_ty: Ty<'tcx>, opt_arg_exprs: Option<&'tcx [hir::Expr<'tcx>]>, ) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> { + // HACK(async_closures): For async closures, prefer `AsyncFn*` + // over `Fn*`, since all async closures implement `FnOnce`, but + // choosing that over `AsyncFn`/`AsyncFnMut` would be more restrictive. + // For other callables, just prefer `Fn*` for perf reasons. + // + // The order of trait choices here is not that big of a deal, + // since it just guides inference (and our choice of autoref). + // Though in the future, I'd like typeck to choose: + // `Fn > AsyncFn > FnMut > AsyncFnMut > FnOnce > AsyncFnOnce` + // ...or *ideally*, we just have `LendingFn`/`LendingFnMut`, which + // would naturally unify these two trait hierarchies in the most + // general way. + let call_trait_choices = if self.shallow_resolve(adjusted_ty).is_coroutine_closure() { + [ + (self.tcx.lang_items().async_fn_trait(), sym::async_call, true), + (self.tcx.lang_items().async_fn_mut_trait(), sym::async_call_mut, true), + (self.tcx.lang_items().async_fn_once_trait(), sym::async_call_once, false), + (self.tcx.lang_items().fn_trait(), sym::call, true), + (self.tcx.lang_items().fn_mut_trait(), sym::call_mut, true), + (self.tcx.lang_items().fn_once_trait(), sym::call_once, false), + ] + } else { + [ + (self.tcx.lang_items().fn_trait(), sym::call, true), + (self.tcx.lang_items().fn_mut_trait(), sym::call_mut, true), + (self.tcx.lang_items().fn_once_trait(), sym::call_once, false), + (self.tcx.lang_items().async_fn_trait(), sym::async_call, true), + (self.tcx.lang_items().async_fn_mut_trait(), sym::async_call_mut, true), + (self.tcx.lang_items().async_fn_once_trait(), sym::async_call_once, false), + ] + }; + // Try the options that are least restrictive on the caller first. - for (opt_trait_def_id, method_name, borrow) in [ - (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), - (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), - (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), - (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true), - ( - self.tcx.lang_items().async_fn_mut_trait(), - Ident::with_dummy_span(sym::async_call_mut), - true, - ), - ( - self.tcx.lang_items().async_fn_once_trait(), - Ident::with_dummy_span(sym::async_call_once), - false, - ), - ] { + for (opt_trait_def_id, method_name, borrow) in call_trait_choices { let Some(trait_def_id) = opt_trait_def_id else { continue }; let opt_input_type = opt_arg_exprs.map(|arg_exprs| { @@ -294,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ok) = self.lookup_method_in_trait( self.misc(call_expr.span), - method_name, + Ident::with_dummy_span(method_name), trait_def_id, adjusted_ty, opt_input_type.as_ref().map(slice::from_ref), diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 58823ea30ce..f21de1609cb 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -448,13 +448,35 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } } - let msg = "an `as` expression can only be used to convert between primitive \ - types or to coerce to a specific trait object"; + + let (msg, note) = if let ty::Adt(adt, _) = self.expr_ty.kind() + && adt.is_enum() + && self.cast_ty.is_numeric() + { + ( + "an `as` expression can be used to convert enum types to numeric \ + types only if the enum type is unit-only or field-less", + Some( + "see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information", + ), + ) + } else { + ( + "an `as` expression can only be used to convert between primitive \ + types or to coerce to a specific trait object", + None, + ) + }; + if label { err.span_label(self.span, msg); } else { err.note(msg); } + + if let Some(note) = note { + err.note(note); + } } else { err.span_label(self.span, "invalid cast"); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a985fa201d0..5bdd9412d0e 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -56,11 +56,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. - let (expected_sig, expected_kind) = match expected.to_option(self) { - Some(ty) => { - self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty)) - } - None => (None, None), + let (expected_sig, expected_kind) = match closure.kind { + hir::ClosureKind::Closure => match expected.to_option(self) { + Some(ty) => { + self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty)) + } + None => (None, None), + }, + // We don't want to deduce a signature from `Fn` bounds for coroutines + // or coroutine-closures, because the former does not implement `Fn` + // ever, and the latter's signature doesn't correspond to the coroutine + // type that it returns. + hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => (None, None), }; let ClosureSignatures { bound_sig, mut liberated_sig } = diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ca636ebcade..2beabc0835d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1715,8 +1715,8 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let ret_msg = "return a value for the case when the loop has zero elements to iterate on"; let ret_ty_msg = "otherwise consider changing the return type to account for that possibility"; - if let Some(node) = tcx.opt_hir_node(item.into()) - && let Some(body_id) = node.body_id() + let node = tcx.hir_node(item.into()); + if let Some(body_id) = node.body_id() && let Some(sig) = node.fn_sig() && let hir::ExprKind::Block(block, _) = hir.body(body_id).value.kind && !ty.is_never() diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b6dfc34d3ac..d8974251de0 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -561,11 +561,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut parent; 'outer: loop { // Climb the HIR tree to see if the current `Expr` is part of a `break;` statement. - let Some( - hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. }) - | hir::Node::Block(hir::Block { expr: Some(&ref p), .. }) - | hir::Node::Expr(&ref p), - ) = self.tcx.opt_hir_node(parent_id) + let (hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. }) + | hir::Node::Block(hir::Block { expr: Some(&ref p), .. }) + | hir::Node::Expr(&ref p)) = self.tcx.hir_node(parent_id) else { break; }; @@ -578,20 +576,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut direct = false; loop { // Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to. - let parent = match self.tcx.opt_hir_node(parent_id) { - Some(hir::Node::Expr(&ref parent)) => { + let parent = match self.tcx.hir_node(parent_id) { + hir::Node::Expr(&ref parent) => { parent_id = self.tcx.hir().parent_id(parent.hir_id); parent } - Some(hir::Node::Stmt(hir::Stmt { + hir::Node::Stmt(hir::Stmt { hir_id, kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent), .. - })) => { + }) => { parent_id = self.tcx.hir().parent_id(*hir_id); parent } - Some(hir::Node::Block(_)) => { + hir::Node::Block(_) => { parent_id = self.tcx.hir().parent_id(parent_id); parent } @@ -680,17 +678,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: Option<TypeError<'tcx>>, ) { let parent = self.tcx.hir().parent_id(expr.hir_id); - match (self.tcx.opt_hir_node(parent), error) { - (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _) + match (self.tcx.hir_node(parent), error) { + (hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _) if init.hir_id == expr.hir_id => { // Point at `let` assignment type. err.span_label(ty.span, "expected due to this"); } ( - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Assign(lhs, rhs, _), .. - })), + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }), Some(TypeError::Sorts(ExpectedFound { expected, .. })), ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => { // We ignore closures explicitly because we already point at them elsewhere. @@ -725,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) => { - if let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id) { + if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) { primary_span = pat.span; secondary_span = pat.span; match self.tcx.hir().find_parent(pat.hir_id) { @@ -774,9 +770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } ( - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Binary(_, lhs, rhs), .. - })), + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(_, lhs, rhs), .. }), Some(TypeError::Sorts(ExpectedFound { expected, .. })), ) if rhs.hir_id == expr.hir_id && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) => @@ -797,8 +791,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else { return; }; - let Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. })) = - self.tcx.opt_hir_node(parent) + let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) = + self.tcx.hir_node(parent) else { return; }; @@ -1022,13 +1016,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Path { res: hir::def::Res::Local(bind_hir_id), .. }, )) = expr.kind { - let bind = self.tcx.opt_hir_node(*bind_hir_id); - let parent = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*bind_hir_id)); - if let Some(hir::Node::Pat(hir::Pat { - kind: hir::PatKind::Binding(_, _hir_id, _, _), - .. - })) = bind - && let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent + let bind = self.tcx.hir_node(*bind_hir_id); + let parent = self.tcx.hir_node(self.tcx.hir().parent_id(*bind_hir_id)); + if let hir::Node::Pat(hir::Pat { + kind: hir::PatKind::Binding(_, _hir_id, _, _), .. + }) = bind + && let hir::Node::Pat(hir::Pat { default_binding_modes: false, .. }) = parent { return true; } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 70afb042441..10e12d01b1f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use crate::fluent_generated as fluent; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, - MultiSpan, SubdiagnosticMessage, + MultiSpan, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -195,10 +195,7 @@ pub struct TypeMismatchFruTypo { } impl AddToDiagnostic for TypeMismatchFruTypo { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -373,10 +370,7 @@ pub struct RemoveSemiForCoerce { } impl AddToDiagnostic for RemoveSemiForCoerce { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret); @@ -547,14 +541,8 @@ pub enum CastUnknownPointerSub { From(Span), } -impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F) - where - F: Fn( - &mut Diagnostic, - rustc_errors::SubdiagnosticMessage, - ) -> rustc_errors::SubdiagnosticMessage, - { +impl AddToDiagnostic for CastUnknownPointerSub { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { match self { CastUnknownPointerSub::To(span) => { let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 54664f38b19..292b85eb97f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1017,7 +1017,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { then: impl FnOnce(&hir::Expr<'_>), ) { let mut parent = self.tcx.hir().parent_id(original_expr_id); - while let Some(node) = self.tcx.opt_hir_node(parent) { + loop { + let node = self.tcx.hir_node(parent); match node { hir::Node::Expr(hir::Expr { kind: @@ -1471,8 +1472,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let hir::TyKind::Array(_, length) = ty.peel_refs().kind && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length - && let Some(span) = self.tcx.hir().opt_span(hir_id) { + let span = self.tcx.hir().span(hir_id); match self.dcx().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { Some(mut err) => { err.span_suggestion( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9935a215009..36c3eef82fc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -521,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// We must not attempt to select obligations after this method has run, or risk query cycle /// ICE. #[instrument(level = "debug", skip(self))] - pub(in super::super) fn resolve_coroutine_interiors(&self, def_id: DefId) { + pub(in super::super) fn resolve_coroutine_interiors(&self) { // Try selecting all obligations that are not blocked on inference variables. // Once we start unifying coroutine witnesses, trying to select obligations on them will // trigger query cycle ICEs, as doing so requires MIR. @@ -1179,14 +1179,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - let arg_count = check_generic_arg_count_for_call( - tcx, - span, - def_id, - generics, - seg, - IsMethodCall::No, - ); + let arg_count = + check_generic_arg_count_for_call(tcx, def_id, generics, seg, IsMethodCall::No); if let ExplicitLateBound::Yes = arg_count.explicit_late_bound { explicit_late_bound = ExplicitLateBound::Yes; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d30c7a4fb38..35b3f27d791 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2060,7 +2060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let node = self .tcx .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id)) - .and_then(|hir_id| self.tcx.opt_hir_node(hir_id)); + .map(|hir_id| self.tcx.hir_node(hir_id)); match node { Some(hir::Node::Item(item)) => call_finder.visit_item(item), Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5395ffda1d1..ed0bdb9bdaa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -682,8 +682,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is and we were expecting a Box, ergo Pin<Box<expected>>, we // can suggest Box::pin. let parent = self.tcx.hir().parent_id(expr.hir_id); - let Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) = - self.tcx.opt_hir_node(parent) + let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) = + self.tcx.hir_node(parent) else { return false; }; @@ -908,9 +908,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Param(expected_ty_as_param) = expected.kind() else { return }; - let fn_node = self.tcx.opt_hir_node(fn_id); + let fn_node = self.tcx.hir_node(fn_id); - let Some(hir::Node::Item(hir::Item { + let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn( hir::FnSig { @@ -921,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _body_id, ), .. - })) = fn_node + }) = fn_node else { return; }; @@ -1053,9 +1053,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let ty = self.normalize(expr.span, ty); if self.can_coerce(found, ty) { - if let Some(node) = self.tcx.opt_hir_node(fn_id) - && let Some(owner_node) = node.as_owner() - && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) + if let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner() + && let Some(span) = expr.span.find_ancestor_inside(*owner_node.span()) { err.multipart_suggestion( "you might have meant to return this value", @@ -1684,15 +1683,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, hir::Path { segments: [_], res: crate::Res::Local(binding), .. }, )) => { - let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.opt_hir_node(*binding) - else { - return expr; - }; - let Some(parent) = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*hir_id)) else { + let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding) else { return expr; }; - match parent { + match self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) { // foo.clone() hir::Node::Local(hir::Local { init: Some(init), .. }) => { self.note_type_is_not_clone_inner_expr(init) @@ -1703,8 +1698,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: hir::PatKind::Tuple(pats, ..), .. }) => { - let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) = - self.tcx.opt_hir_node(self.tcx.hir().parent_id(*pat_hir_id)) + let hir::Node::Local(hir::Local { init: Some(init), .. }) = + self.tcx.hir_node(self.tcx.hir().parent_id(*pat_hir_id)) else { return expr; }; @@ -1736,10 +1731,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_kind && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path - && let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = - self.tcx.opt_hir_node(*binding) - && let Some(closure) = self.tcx.opt_hir_node(self.tcx.hir().parent_id(*hir_id)) - && let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure + && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding) + && let hir::Node::Local(hir::Local { init: Some(init), .. }) = + self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) && let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), .. @@ -1979,20 +1973,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Unroll desugaring, to make sure this works for `for` loops etc. loop { parent = self.tcx.hir().parent_id(id); - if let Some(parent_span) = self.tcx.hir().opt_span(parent) { - if parent_span.find_ancestor_inside(expr.span).is_some() { - // The parent node is part of the same span, so is the result of the - // same expansion/desugaring and not the 'real' parent node. - id = parent; - continue; - } + let parent_span = self.tcx.hir().span(parent); + if parent_span.find_ancestor_inside(expr.span).is_some() { + // The parent node is part of the same span, so is the result of the + // same expansion/desugaring and not the 'real' parent node. + id = parent; + continue; } break; } - if let Some(hir::Node::Block(&hir::Block { - span: block_span, expr: Some(e), .. - })) = self.tcx.opt_hir_node(parent) + if let hir::Node::Block(&hir::Block { span: block_span, expr: Some(e), .. }) = + self.tcx.hir_node(parent) { if e.hir_id == id { if let Some(span) = expr.span.find_ancestor_inside(block_span) { @@ -2220,30 +2212,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let local_parent = self.tcx.hir().parent_id(local_id); - let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = - self.tcx.opt_hir_node(local_parent) + let Node::Param(hir::Param { hir_id: param_hir_id, .. }) = self.tcx.hir_node(local_parent) else { return None; }; let param_parent = self.tcx.hir().parent_id(*param_hir_id); - let Some(Node::Expr(hir::Expr { + let Node::Expr(hir::Expr { hir_id: expr_hir_id, kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }), .. - })) = self.tcx.opt_hir_node(param_parent) + }) = self.tcx.hir_node(param_parent) else { return None; }; let expr_parent = self.tcx.hir().parent_id(*expr_hir_id); - let hir = self.tcx.opt_hir_node(expr_parent); + let hir = self.tcx.hir_node(expr_parent); let closure_params_len = closure_fn_decl.inputs.len(); let ( - Some(Node::Expr(hir::Expr { + Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(method_path, receiver, ..), .. - })), + }), 1, ) = (hir, closure_params_len) else { @@ -2674,10 +2665,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool { if let hir::ExprKind::If(..) = expr.kind { let parent_id = self.tcx.hir().parent_id(expr.hir_id); - if let Some(Node::Expr(hir::Expr { - kind: hir::ExprKind::If(_, _, Some(else_expr)), - .. - })) = self.tcx.opt_hir_node(parent_id) + if let Node::Expr(hir::Expr { + kind: hir::ExprKind::If(_, _, Some(else_expr)), .. + }) = self.tcx.hir_node(parent_id) { return else_expr.hir_id == expr.hir_id; } @@ -3067,7 +3057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; let parent = self.tcx.hir().parent_id(expr.hir_id); - if let Some(hir::Node::ExprField(_)) = self.tcx.opt_hir_node(parent) { + if let hir::Node::ExprField(_) = self.tcx.hir_node(parent) { // Ignore `Foo { field: a..Default::default() }` return; } @@ -3146,7 +3136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::def::Res::Local(hir_id) = path.res else { return; }; - let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(hir_id) else { + let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else { return; }; let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index deb3ad2edc7..315dc4330ad 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(try_blocks)] @@ -286,7 +288,7 @@ fn typeck_with_fallback<'tcx>( debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); // This must be the last thing before `report_ambiguity_errors`. - fcx.resolve_coroutine_interiors(def_id.to_def_id()); + fcx.resolve_coroutine_interiors(); debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations()); diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 1ce0240f7b8..f9297550c57 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -436,7 +436,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { pub(crate) fn cat_rvalue( &self, hir_id: hir::HirId, - span: Span, + // FIXME: remove + _span: Span, expr_ty: Ty<'tcx>, ) -> PlaceWithHirId<'tcx> { PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index c8a235761de..3a44c6c2410 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -356,7 +356,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let arg_count_correct = check_generic_arg_count_for_call( self.tcx, - self.span, pick.item.def_id, generics, seg, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 007df203f71..81b82393515 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -230,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind && let hir::def::Res::Local(hir_id) = path.res - && let Some(hir::Node::Pat(b)) = self.tcx.opt_hir_node(hir_id) + && let hir::Node::Pat(b) = self.tcx.hir_node(hir_id) && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id) && let Some(node) = self.tcx.hir().find_parent(p.hir_id) && let Some(decl) = node.fn_decl() @@ -2017,7 +2017,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { visitor.visit_body(body); let parent = self.tcx.hir().parent_id(seg1.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.opt_hir_node(parent) + if let Node::Expr(call_expr) = self.tcx.hir_node(parent) && let Some(expr) = visitor.result && let Some(self_ty) = self.node_ty_opt(expr.hir_id) { @@ -3251,7 +3251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let parent = self.tcx.hir().parent_id(expr.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.opt_hir_node(parent) + if let Node::Expr(call_expr) = self.tcx.hir_node(parent) && let hir::ExprKind::MethodCall( hir::PathSegment { ident: method_name, .. }, self_expr, diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index b9b3ed53dae..34ce0ab1f8b 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -73,9 +73,7 @@ pub fn resolve_rvalue_scopes<'a, 'tcx>( debug!("start resolving rvalue scopes, def_id={def_id:?}"); debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates); for (&hir_id, candidate) in &scope_tree.rvalue_candidates { - let Some(Node::Expr(expr)) = tcx.opt_hir_node(hir_id) else { - bug!("hir node does not exist") - }; + let Node::Expr(expr) = tcx.hir_node(hir_id) else { bug!("hir node does not exist") }; record_rvalue_scope(&mut rvalue_scopes, expr, candidate); } rvalue_scopes diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index c4773a88521..211109b5941 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -972,9 +972,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { if s.starts_with('$') { // Looks like a macro fragment. Try to find the real block. - if let Some(hir::Node::Expr(&hir::Expr { + if let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Block(block, ..), .. - })) = self.tcx.opt_hir_node(body_id.hir_id) { + }) = self.tcx.hir_node(body_id.hir_id) { // If the body is a block (with `{..}`), we use the span of that block. // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. // Since we know it's a block, we know we can insert the `let _ = ..` without diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 3430a5fb00d..94f6c06157e 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -753,10 +753,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed { - match self.fcx.dcx().has_errors() { - Some(e) => e, - None => self - .fcx + if let Some(guar) = self.fcx.dcx().has_errors() { + guar + } else if self.fcx.dcx().stashed_err_count() > 0 { + // Without this case we sometimes get uninteresting and extraneous + // "type annotations needed" errors. + self.fcx.dcx().delayed_bug("error in Resolver") + } else { + self.fcx .err_ctxt() .emit_inference_failure_err( self.fcx.tcx.hir().body_owner_def_id(self.body.id()), @@ -765,7 +769,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { E0282, false, ) - .emit(), + .emit() } } diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 82f02b7d47a..0729986f32f 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,8 +5,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 854841206b8..6fcb3a024ab 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![cfg_attr( feature = "nightly", feature(extend_one, min_specialization, new_uninit, step_trait, test) diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs index 72567b43a5f..532cac5791e 100644 --- a/compiler/rustc_index_macros/src/lib.rs +++ b/compiler/rustc_index_macros/src/lib.rs @@ -31,17 +31,17 @@ mod newtype; /// - `#[max = 0xFFFF_FFFD]`: specifies the max value, which allows niche /// optimizations. The default max value is 0xFFFF_FF00. /// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only. -/// -/// `SpecOptionPartialEq` is specialized by this macro, so using it requires enabling -/// `#![feature(min_specialization)]` for the crate. #[proc_macro] #[cfg_attr( feature = "nightly", - allow_internal_unstable(step_trait, rustc_attrs, trusted_step, spec_option_partial_eq) + allow_internal_unstable( + step_trait, + rustc_attrs, + trusted_step, + spec_option_partial_eq, + min_specialization + ) )] -// FIXME: Remove the above comment about `min_specialization` once bootstrap is bumped, -// and the corresponding one on SpecOptionPartialEq -#[cfg_attr(all(feature = "nightly", not(bootstrap)), allow_internal_unstable(min_specialization))] pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 0a128218c92..8bfc05d6a96 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,7 +1,7 @@ use hir::GenericParamKind; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, - DiagnosticStyledString, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, + DiagnosticStyledString, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessageOp, }; use rustc_hir as hir; use rustc_hir::FnRetTy; @@ -225,10 +225,7 @@ pub enum RegionOriginNote<'a> { } impl AddToDiagnostic for RegionOriginNote<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let mut label_or_note = |span, msg: DiagnosticMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -289,10 +286,7 @@ pub enum LifetimeMismatchLabels { } impl AddToDiagnostic for LifetimeMismatchLabels { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::infer_declared_different); @@ -336,10 +330,7 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let mut mk_suggestion = || { let ( hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. }, @@ -437,10 +428,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(mut self, diag: &mut Diagnostic, _: F) { self.unmet_requirements .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); @@ -755,10 +743,7 @@ pub struct ConsiderBorrowingParamHelp { } impl AddToDiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into<DiagnosticMessage> is required @@ -799,10 +784,7 @@ pub struct DynTraitConstraintSuggestion { } impl AddToDiagnostic for DynTraitConstraintSuggestion { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); @@ -845,10 +827,7 @@ pub struct ReqIntroducedLocations { } impl AddToDiagnostic for ReqIntroducedLocations { - fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(mut self, diag: &mut Diagnostic, f: F) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer_ril_introduced_here); } @@ -867,10 +846,7 @@ pub struct MoreTargeted { } impl AddToDiagnostic for MoreTargeted { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _f: F) { diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); diag.arg("ident", self.ident); @@ -1289,10 +1265,7 @@ pub struct SuggestTuplePatternMany { } impl AddToDiagnostic for SuggestTuplePatternMany { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diag.multipart_suggestions( diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 331e3633e90..a59a4df7729 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,6 +1,6 @@ use crate::fluent_generated as fluent; use crate::infer::error_reporting::nice_region_error::find_anon_type; -use rustc_errors::{AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessage}; +use rustc_errors::{AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessageOp}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; @@ -160,10 +160,7 @@ impl RegionExplanation<'_> { } impl AddToDiagnostic for RegionExplanation<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0f1af81d9f0..859593e1194 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -87,6 +87,7 @@ impl<'tcx> InferCtxt<'tcx> { reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), err_count_on_creation: self.err_count_on_creation, + stashed_err_count_on_creation: self.stashed_err_count_on_creation, universe: self.universe.clone(), intercrate, next_trait_solver: self.next_trait_solver, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 59bed38ec2a..dd9ed80ca72 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2182,8 +2182,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let Some(tykind) = tykind && let hir::TyKind::Array(_, length) = tykind && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length - && let Some(span) = self.tcx.hir().opt_span(*hir_id) { + let span = self.tcx.hir().span(*hir_id); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) } else { None diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2d8b47a9cc0..78ef70398e5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -306,6 +306,12 @@ pub struct InferCtxt<'tcx> { // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, + /// Track how many errors were stashed when this infcx is created. + /// Used for the same purpose as `err_count_on_creation`, even + /// though it's weaker because the count can go up and down. + // FIXME(matthewjasper) Merge into `tainted_by_errors` + stashed_err_count_on_creation: usize, + /// What is the innermost universe we have created? Starts out as /// `UniverseIndex::root()` but grows from there as we enter /// universal quantifiers. @@ -711,6 +717,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.dcx().err_count(), + stashed_err_count_on_creation: tcx.dcx().stashed_err_count(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, next_trait_solver, @@ -863,7 +870,7 @@ impl<'tcx> InferCtxt<'tcx> { } #[instrument(skip(self, snapshot), level = "debug")] - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) { + fn rollback_to(&self, snapshot: CombinedSnapshot<'tcx>) { let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot; self.universe.set(universe); @@ -895,7 +902,7 @@ impl<'tcx> InferCtxt<'tcx> { self.commit_from(snapshot); } Err(_) => { - self.rollback_to("commit_if_ok -- error", snapshot); + self.rollback_to(snapshot); } } r @@ -909,7 +916,7 @@ impl<'tcx> InferCtxt<'tcx> { { let snapshot = self.start_snapshot(); let r = f(&snapshot); - self.rollback_to("probe", snapshot); + self.rollback_to(snapshot); r } @@ -1032,10 +1039,9 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - let ty::SubtypePredicate { a_is_expected, a, b } = - self.instantiate_binder_with_placeholders(predicate); - - Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) + self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { + Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)) + }) } pub fn region_outlives_predicate( @@ -1043,10 +1049,12 @@ impl<'tcx> InferCtxt<'tcx> { cause: &traits::ObligationCause<'tcx>, predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) { - let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate); - let origin = - SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span)); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| { + let origin = SubregionOrigin::from_obligation_cause(cause, || { + RelateRegionParamBound(cause.span) + }); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + }) } /// Number of type variables created so far. @@ -1261,26 +1269,24 @@ impl<'tcx> InferCtxt<'tcx> { /// inference variables, regionck errors). #[must_use = "this method does not have any side effects"] pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { - debug!( - "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors={})", - self.dcx().err_count(), - self.err_count_on_creation, - self.tainted_by_errors.get().is_some() - ); - - if let Some(e) = self.tainted_by_errors.get() { - return Some(e); - } - - if self.dcx().err_count() > self.err_count_on_creation { - // errors reported since this infcx was made - let e = self.dcx().has_errors().unwrap(); - self.set_tainted_by_errors(e); - return Some(e); + if let Some(guar) = self.tainted_by_errors.get() { + Some(guar) + } else if self.dcx().err_count() > self.err_count_on_creation { + // Errors reported since this infcx was made. + let guar = self.dcx().has_errors().unwrap(); + self.set_tainted_by_errors(guar); + Some(guar) + } else if self.dcx().stashed_err_count() > self.stashed_err_count_on_creation { + // Errors stashed since this infcx was made. Not entirely reliable + // because the count of stashed errors can go down. But without + // this case we get a moderate number of uninteresting and + // extraneous "type annotations needed" errors. + let guar = self.dcx().delayed_bug("tainted_by_errors: stashed bug awaiting emission"); + self.set_tainted_by_errors(guar); + Some(guar) + } else { + None } - - None } /// Set the "tainted by errors" flag to true. We call this when we @@ -1455,7 +1461,7 @@ impl<'tcx> InferCtxt<'tcx> { // Use this method if you'd like to find some substitution of the binder's // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] // that corresponds to your use case, consider whether or not you should - // use [`InferCtxt::instantiate_binder_with_placeholders`] instead. + // use [`InferCtxt::enter_forall`] instead. pub fn instantiate_binder_with_fresh_vars<T>( &self, span: Span, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 5ee0a606a5f..46c4f80cb0c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -327,7 +327,6 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] pub fn register_member_constraints( &self, - param_env: ty::ParamEnv<'tcx>, opaque_type_key: OpaqueTypeKey<'tcx>, concrete_ty: Ty<'tcx>, span: Span, @@ -687,7 +686,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi let res = hir_id == scope; trace!( "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", - tcx.opt_hir_node(hir_id), + tcx.hir_node(hir_id), tcx.hir_node(opaque_hir_id), res ); diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 13c17ee1cd2..7edfbf02a68 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -221,11 +221,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b, relation.param_env()); + return self.unify_const_variable(vid, b); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a, relation.param_env()); + return self.unify_const_variable(vid, a); } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { @@ -298,7 +298,6 @@ impl<'tcx> InferCtxt<'tcx> { &self, target_vid: ty::ConstVid, ct: ty::Const<'tcx>, - param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { ConstVariableValue::Known { value } => { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 440df8c8936..90be80f67b4 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -38,24 +38,25 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. Note that this automatically creates // a new universe if needed. - let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup); + self.infcx.enter_forall(sup, |sup_prime| { + // Next, we instantiate each bound region in the subtype + // with a fresh region variable. These region variables -- + // but no other preexisting region variables -- can name + // the placeholders. + let sub_prime = + self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); + debug!("a_prime={:?}", sub_prime); + debug!("b_prime={:?}", sup_prime); - // Next, we instantiate each bound region in the subtype - // with a fresh region variable. These region variables -- - // but no other preexisting region variables -- can name - // the placeholders. - let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); - - debug!("a_prime={:?}", sub_prime); - debug!("b_prime={:?}", sup_prime); - - // Compare types now that bound regions have been replaced. - let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?; - - debug!("OK result={result:?}"); - // NOTE: returning the result here would be dangerous as it contains - // placeholders which **must not** be named afterwards. - Ok(()) + // Compare types now that bound regions have been replaced. + let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime); + if result.is_ok() { + debug!("OK result={result:?}"); + } + // NOTE: returning the result here would be dangerous as it contains + // placeholders which **must not** be named afterwards. + result.map(|_| ()) + }) } } @@ -68,9 +69,11 @@ impl<'tcx> InferCtxt<'tcx> { /// This is the first step of checking subtyping when higher-ranked things are involved. /// For more details visit the relevant sections of the [rustc dev guide]. /// + /// `fn enter_forall` should be preferred over this method. + /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[instrument(level = "debug", skip(self), ret)] - pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T + pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<TyCtxt<'tcx>> + Copy, { @@ -106,6 +109,31 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.replace_bound_vars_uncached(binder, delegate) } + /// Replaces all bound variables (lifetimes, types, and constants) bound by + /// `binder` with placeholder variables in a new universe and then calls the + /// closure `f` with the instantiated value. The new placeholders can only be + /// named by inference variables created inside of the closure `f` or afterwards. + /// + /// This is the first step of checking subtyping when higher-ranked things are involved. + /// For more details visit the relevant sections of the [rustc dev guide]. + /// + /// This method should be preferred over `fn enter_forall_and_leak_universe`. + /// + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html + #[instrument(level = "debug", skip(self, f))] + pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U + where + T: TypeFoldable<TyCtxt<'tcx>> + Copy, + { + // FIXME: currently we do nothing to prevent placeholders with the new universe being + // used after exiting `f`. For example region subtyping can result in outlives constraints + // that name placeholders created in this function. Nested goals from type relations can + // also contain placeholders created by this function. + let value = self.enter_forall_and_leak_universe(forall); + debug!("?value"); + f(value) + } + /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that /// universe. diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 8b80646a386..5e2d2af9b85 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -261,52 +261,55 @@ where Ok(a) } - #[instrument(skip(self), level = "debug")] - fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T + fn enter_forall<T, U>( + &mut self, + binder: ty::Binder<'tcx, T>, + f: impl FnOnce(&mut Self, T) -> U, + ) -> U where T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy, { - if let Some(inner) = binder.no_bound_vars() { - return inner; - } - - let mut next_region = { - let nll_delegate = &mut self.delegate; - let mut lazy_universe = None; + let value = if let Some(inner) = binder.no_bound_vars() { + inner + } else { + let mut next_region = { + let nll_delegate = &mut self.delegate; + let mut lazy_universe = None; + + move |br: ty::BoundRegion| { + // The first time this closure is called, create a + // new universe for the placeholders we will make + // from here out. + let universe = lazy_universe.unwrap_or_else(|| { + let universe = nll_delegate.create_next_universe(); + lazy_universe = Some(universe); + universe + }); + + let placeholder = ty::PlaceholderRegion { universe, bound: br }; + debug!(?placeholder); + let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); + debug!(?placeholder_reg); + + placeholder_reg + } + }; - move |br: ty::BoundRegion| { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = nll_delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, bound: br }; - debug!(?placeholder); - let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); - debug!(?placeholder_reg); - - placeholder_reg - } - }; + let delegate = FnMutDelegate { + regions: &mut next_region, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; - let delegate = FnMutDelegate { - regions: &mut next_region, - types: &mut |_bound_ty: ty::BoundTy| { - unreachable!("we only replace regions in nll_relate, not types") - }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { - unreachable!("we only replace regions in nll_relate, not consts") - }, + self.infcx.tcx.replace_bound_vars_uncached(binder, delegate) }; - let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); - debug!(?replaced); - - replaced + debug!(?value); + f(self, value) } #[instrument(skip(self), level = "debug")] @@ -630,10 +633,10 @@ where // Note: the order here is important. Create the placeholders first, otherwise // we assign the wrong universe to the existential! - let b_replaced = self.instantiate_binder_with_placeholders(b); - let a_replaced = self.instantiate_binder_with_existentials(a); - - self.relate(a_replaced, b_replaced)?; + self.enter_forall(b, |this, b| { + let a = this.instantiate_binder_with_existentials(a); + this.relate(a, b) + })?; self.ambient_variance = variance; } @@ -650,10 +653,10 @@ where let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - let a_replaced = self.instantiate_binder_with_placeholders(a); - let b_replaced = self.instantiate_binder_with_existentials(b); - - self.relate(a_replaced, b_replaced)?; + self.enter_forall(a, |this, a| { + let b = this.instantiate_binder_with_existentials(b); + this.relate(a, b) + })?; self.ambient_variance = variance; } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index e2dd4b49e1a..622cdf0c7b8 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,6 +16,8 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(extend_one)] diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index eabc1b953af..7401654aea8 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::Map; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; @@ -62,7 +61,7 @@ pub fn report_object_safety_error<'tcx>( err.span_label(span, format!("`{trait_str}` cannot be made into an object")); if let Some(hir_id) = hir_id - && let Some(hir::Node::Ty(ty)) = tcx.hir().find(hir_id) + && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind { let mut hir_id = hir_id; @@ -178,12 +177,13 @@ pub fn report_object_safety_error<'tcx>( ))); } impls => { - let types = impls + let mut types = impls .iter() .map(|t| { with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) }) .collect::<Vec<_>>(); + types.sort(); err.help(format!( "the following types implement the trait, consider defining an enum where each \ variant holds one of these types, implementing `{}` for this new enum and using \ diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 69414a13795..7d69e49b209 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,8 +4,6 @@ #![feature(let_chains)] #![feature(thread_spawn_unchecked)] #![feature(try_blocks)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 97956404120..50b2bf7da15 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -778,6 +778,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // kindck is gone now). -nmatsakis if let Some(reported) = sess.dcx().has_errors() { return Err(reported); + } else if sess.dcx().stashed_err_count() > 0 { + // Without this case we sometimes get delayed bug ICEs and I don't + // understand why. -nnethercote + return Err(sess.dcx().delayed_bug("some stashed error is waiting for use")); } sess.time("misc_checking_3", || { diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f6c9289b529..ca84e930c24 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -18,8 +18,7 @@ //! lexeme types. //! //! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] + // We want to be able to build this crate with a stable compiler, // so no `#![feature]` attributes should be added. #![deny(unstable_features)] diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 3bd0c1b8031..21d4b6fa65b 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,5 +1,5 @@ use crate::fluent_generated as fluent; -use rustc_errors::{codes::*, AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; +use rustc_errors::{codes::*, AddToDiagnostic, Diagnostic, SubdiagnosticMessageOp}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -24,10 +24,7 @@ pub enum OverruledAttributeSub { } impl AddToDiagnostic for OverruledAttributeSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index eb2490a47d0..516df14c894 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -345,7 +345,7 @@ declare_tool_lint! { /// /// More details on translatable diagnostics can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html). pub rustc::UNTRANSLATABLE_DIAGNOSTIC, - Allow, + Deny, "prevent creation of diagnostics which cannot be translated", report_in_external_macro: true } @@ -357,7 +357,7 @@ declare_tool_lint! { /// /// More details on diagnostics implementations can be found [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html). pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL, - Allow, + Deny, "prevent creation of diagnostics outside of `IntoDiagnostic`/`AddToDiagnostic` impls", report_in_external_macro: true } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index caa01556591..d3d7698e7f9 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -364,14 +364,11 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // Note: `passes` is often empty. In that case, it's faster to run // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. - let mut passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_module_passes - .iter() - .map(|mk_pass| (mk_pass)(tcx)) - .collect(); - if passes.is_empty() { + let late_module_passes = &unerased_lint_store(tcx.sess).late_module_passes; + if late_module_passes.is_empty() { late_lint_mod_inner(tcx, module_def_id, context, builtin_lints); } else { + let mut passes: Vec<_> = late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); passes.push(Box::new(builtin_lints)); let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; late_lint_mod_inner(tcx, module_def_id, context, pass); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1c03de410ee..5c2a422a2b7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -34,11 +34,9 @@ #![feature(if_let_guard)] #![feature(iter_order_by)] #![feature(let_chains)] -#![cfg_attr(not(bootstrap), feature(trait_upcasting))] +#![feature(trait_upcasting)] #![feature(min_specialization)] #![feature(rustc_attrs)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index f916deb4a46..42d9760f8aa 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,12 +1,13 @@ -#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use std::num::NonZeroU32; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, DiagnosticStyledString, SubdiagnosticMessage, SuggestionStyle, + DiagnosticMessage, DiagnosticStyledString, SubdiagnosticMessageOp, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -268,10 +269,7 @@ pub struct SuggestChangingAssocTypes<'a, 'b> { } impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { // Access to associates types should use `<T as Bound>::Assoc`, which does not need a // bound. Let's see if this type does that. @@ -323,10 +321,7 @@ pub struct BuiltinTypeAliasGenericBoundsSuggestion { } impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.multipart_suggestion( fluent::lint_suggestion, self.suggestions, @@ -443,10 +438,7 @@ pub struct BuiltinUnpermittedTypeInitSub { } impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -497,10 +489,7 @@ pub struct BuiltinClashingExternSub<'a> { } impl AddToDiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let mut expected_str = DiagnosticStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagnosticStyledString::new(); @@ -766,10 +755,7 @@ pub struct HiddenUnicodeCodepointsDiagLabels { } impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -783,10 +769,7 @@ pub enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( @@ -934,10 +917,7 @@ pub struct NonBindingLetSub { } impl AddToDiagnostic for NonBindingLetSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1217,10 +1197,7 @@ pub enum NonSnakeCaseDiagSub { } impl AddToDiagnostic for NonSnakeCaseDiagSub { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, fluent::lint_label); @@ -1413,10 +1390,7 @@ pub enum OverflowingBinHexSign { } impl AddToDiagnostic for OverflowingBinHexSign { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { OverflowingBinHexSign::Positive => { diag.note(fluent::lint_positive_note); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index bed5d3c80c0..cf825be7a55 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -77,101 +77,104 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { - let predicate = infcx.instantiate_binder_with_placeholders(pred.kind()); - let ty::ClauseKind::Projection(proj) = predicate else { - continue; - }; - // Only check types, since those are the only things that may - // have opaques in them anyways. - let Some(proj_term) = proj.term.ty() else { continue }; + infcx.enter_forall(pred.kind(), |predicate| { + let ty::ClauseKind::Projection(proj) = predicate else { + return; + }; + // Only check types, since those are the only things that may + // have opaques in them anyways. + let Some(proj_term) = proj.term.ty() else { return }; - // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... - if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() - && cx.tcx.parent(opaque_ty.def_id) == def_id - && matches!( - opaque.origin, - hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) - ) - { - continue; - } + // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... + if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() + && cx.tcx.parent(opaque_ty.def_id) == def_id + && matches!( + opaque.origin, + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) + ) + { + return; + } - // HACK: `async fn() -> Self` in traits is "ok"... - // This is not really that great, but it's similar to why the `-> Self` - // return type is well-formed in traits even when `Self` isn't sized. - if let ty::Param(param_ty) = *proj_term.kind() - && param_ty.name == kw::SelfUpper - && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) - && opaque.in_trait - { - continue; - } + // HACK: `async fn() -> Self` in traits is "ok"... + // This is not really that great, but it's similar to why the `-> Self` + // return type is well-formed in traits even when `Self` isn't sized. + if let ty::Param(param_ty) = *proj_term.kind() + && param_ty.name == kw::SelfUpper + && matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(_)) + && opaque.in_trait + { + return; + } - let proj_ty = - Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args); - // For every instance of the projection type in the bounds, - // replace them with the term we're assigning to the associated - // type in our opaque type. - let proj_replacer = &mut BottomUpFolder { - tcx: cx.tcx, - ty_op: |ty| if ty == proj_ty { proj_term } else { ty }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }; - // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`, - // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait` - // with `impl Send: OtherTrait`. - for (assoc_pred, assoc_pred_span) in cx - .tcx - .explicit_item_bounds(proj.projection_ty.def_id) - .iter_instantiated_copied(cx.tcx, proj.projection_ty.args) - { - let assoc_pred = assoc_pred.fold_with(proj_replacer); - let Ok(assoc_pred) = traits::fully_normalize( - infcx, - traits::ObligationCause::dummy(), - cx.param_env, - assoc_pred, - ) else { - continue; + let proj_ty = + Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args); + // For every instance of the projection type in the bounds, + // replace them with the term we're assigning to the associated + // type in our opaque type. + let proj_replacer = &mut BottomUpFolder { + tcx: cx.tcx, + ty_op: |ty| if ty == proj_ty { proj_term } else { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, }; - // If that predicate doesn't hold modulo regions (but passed during type-check), - // then we must've taken advantage of the hack in `project_and_unify_types` where - // we replace opaques with inference vars. Emit a warning! - if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( - cx.tcx, - traits::ObligationCause::dummy(), - cx.param_env, - assoc_pred, - )) { - // If it's a trait bound and an opaque that doesn't satisfy it, - // then we can emit a suggestion to add the bound. - let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { - ( - ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), - ty::ClauseKind::Trait(trait_pred), - ) => Some(AddBound { - suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), - trait_ref: trait_pred.print_modifiers_and_trait_path(), - }), - _ => None, + // For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`, + // e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait` + // with `impl Send: OtherTrait`. + for (assoc_pred, assoc_pred_span) in cx + .tcx + .explicit_item_bounds(proj.projection_ty.def_id) + .iter_instantiated_copied(cx.tcx, proj.projection_ty.args) + { + let assoc_pred = assoc_pred.fold_with(proj_replacer); + let Ok(assoc_pred) = traits::fully_normalize( + infcx, + traits::ObligationCause::dummy(), + cx.param_env, + assoc_pred, + ) else { + continue; }; - cx.emit_span_lint( - OPAQUE_HIDDEN_INFERRED_BOUND, - pred_span, - OpaqueHiddenInferredBoundLint { - ty: Ty::new_opaque( - cx.tcx, - def_id, - ty::GenericArgs::identity_for_item(cx.tcx, def_id), - ), - proj_ty: proj_term, - assoc_pred_span, - add_bound, - }, - ); + + // If that predicate doesn't hold modulo regions (but passed during type-check), + // then we must've taken advantage of the hack in `project_and_unify_types` where + // we replace opaques with inference vars. Emit a warning! + if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new( + cx.tcx, + traits::ObligationCause::dummy(), + cx.param_env, + assoc_pred, + )) { + // If it's a trait bound and an opaque that doesn't satisfy it, + // then we can emit a suggestion to add the bound. + let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { + ( + ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), + ty::ClauseKind::Trait(trait_pred), + ) => Some(AddBound { + suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(), + trait_ref: trait_pred.print_modifiers_and_trait_path(), + }), + _ => None, + }; + + cx.emit_span_lint( + OPAQUE_HIDDEN_INFERRED_BOUND, + pred_span, + OpaqueHiddenInferredBoundLint { + ty: Ty::new_opaque( + cx.tcx, + def_id, + ty::GenericArgs::identity_for_item(cx.tcx, def_id), + ), + proj_ty: proj_term, + assoc_pred_span, + add_bound, + }, + ); + } } - } + }); } } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index eed35326c45..8b7e82d2113 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,6 +1,4 @@ #![feature(min_specialization)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index ca0aec71052..6a570c97c88 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index e3464cb8a2d..1a78f9f0f86 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -38,9 +38,6 @@ //! debugging, you can make changes inside those crates and quickly run main.rs //! to read the debug logs. -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] - use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io::{self, IsTerminal}; diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index c029b931e7d..3a5f289559e 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -89,10 +89,7 @@ impl SubdiagnosticDeriveBuilder { gen impl rustc_errors::AddToDiagnostic for @Self { fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F) where - __F: core::ops::Fn( - &mut rustc_errors::Diagnostic, - rustc_errors::SubdiagnosticMessage - ) -> rustc_errors::SubdiagnosticMessage, + __F: rustc_errors::SubdiagnosticMessageOp, { #implementation } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 9e85a59b5b9..af65c908ee6 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -6,8 +6,6 @@ #![feature(proc_macro_span)] #![feature(proc_macro_tracked_env)] #![allow(rustc::default_hash_types)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] use synstructure::decl_derive; diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index bb02a8a1e47..c18f0e7b7b9 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -534,7 +534,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { ) -> Option<CrateNum> { self.used_extern_options.insert(name); match self.maybe_resolve_crate(name, dep_kind, None) { - Ok(cnum) => Some(cnum), + Ok(cnum) => { + self.cstore.set_used_recursively(cnum); + Some(cnum) + } Err(err) => { let missing_core = self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); @@ -1067,6 +1070,16 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> { self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() } + + pub fn unload_unused_crates(&mut self) { + for opt_cdata in &mut self.cstore.metas { + if let Some(cdata) = opt_cdata + && !cdata.used() + { + *opt_cdata = None; + } + } + } } fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 471425e8017..2e7130f3565 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -15,8 +15,6 @@ #![feature(try_blocks)] #![feature(never_type)] #![allow(rustc::potential_query_instability)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] extern crate proc_macro; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 20e3ae3ba94..11cb1bb6d9e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -106,6 +106,8 @@ pub(crate) struct CrateMetadata { private_dep: bool, /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`. host_hash: Option<Svh>, + /// The crate was used non-speculatively. + used: bool, /// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext` /// and `ExpnId`). @@ -1811,6 +1813,7 @@ impl CrateMetadata { source: Lrc::new(source), private_dep, host_hash, + used: false, extern_crate: None, hygiene_context: Default::default(), def_key_cache: Default::default(), @@ -1860,6 +1863,10 @@ impl CrateMetadata { self.private_dep &= private_dep; } + pub(crate) fn used(&self) -> bool { + self.used + } + pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> { self.root.required_panic_strategy } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0b352a02b64..7cd2f58779f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; use std::any::Any; +use std::mem; use super::{Decodable, DecodeContext, DecodeIterator}; @@ -576,12 +577,24 @@ impl CStore { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } + pub fn set_used_recursively(&mut self, cnum: CrateNum) { + let cmeta = self.get_crate_data_mut(cnum); + if !cmeta.used { + cmeta.used = true; + let dependencies = mem::take(&mut cmeta.dependencies); + for &dep_cnum in &dependencies { + self.set_used_recursively(dep_cnum); + } + self.get_crate_data_mut(cnum).dependencies = dependencies; + } + } + pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) { let cmeta = self.get_crate_data_mut(cnum); if cmeta.update_extern_crate(extern_crate) { // Propagate the extern crate info to dependencies if it was updated. let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; - let dependencies = std::mem::take(&mut cmeta.dependencies); + let dependencies = mem::take(&mut cmeta.dependencies); for &dep_cnum in &dependencies { self.update_extern_crate(dep_cnum, extern_crate); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 85631bd8edb..79aa9a547f7 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1388,13 +1388,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_fn_sig(def_kind) { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } - // FIXME: Some anonymous constants produced by `#[rustc_legacy_const_generics]` - // do not have corresponding HIR nodes, so some queries usually making sense for - // anonymous constants will not work on them and panic. It's not clear whether it - // can cause any observable issues or not. - let anon_const_without_hir = def_kind == DefKind::AnonConst - && tcx.opt_hir_node(tcx.local_def_id_to_hir_id(local_id)).is_none(); - if should_encode_generics(def_kind) && !anon_const_without_hir { + if should_encode_generics(def_kind) { let g = tcx.generics_of(def_id); record!(self.tables.generics_of[def_id] <- g); record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id)); @@ -1408,7 +1402,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - if should_encode_type(tcx, local_id, def_kind) && !anon_const_without_hir { + if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } if should_encode_constness(def_kind) { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ba1ae46626b..bf72aac1033 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -158,22 +158,14 @@ impl<'tcx> TyCtxt<'tcx> { } /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found. - pub fn opt_hir_node(self, id: HirId) -> Option<Node<'tcx>> { - let owner = self.hir_owner_nodes(id.owner); - let node = owner.nodes[id.local_id].as_ref()?; - Some(node.node) - } - - /// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found. #[inline] pub fn opt_hir_node_by_def_id(self, id: LocalDefId) -> Option<Node<'tcx>> { - self.opt_hir_node(self.opt_local_def_id_to_hir_id(id)?) + Some(self.hir_node(self.opt_local_def_id_to_hir_id(id)?)) } - /// Retrieves the `hir::Node` corresponding to `id`, panicking if it cannot be found. - #[track_caller] + /// Retrieves the `hir::Node` corresponding to `id`. pub fn hir_node(self, id: HirId) -> Node<'tcx> { - self.opt_hir_node(id).unwrap_or_else(|| bug!("couldn't find HIR node for hir id {id:?}")) + self.hir_owner_nodes(id.owner).nodes[id.local_id].node } /// Retrieves the `hir::Node` corresponding to `id`, panicking if it cannot be found. @@ -230,10 +222,13 @@ impl<'hir> Map<'hir> { /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. pub fn opt_parent_id(self, id: HirId) -> Option<HirId> { if id.local_id == ItemLocalId::from_u32(0) { + // FIXME: This function never returns `None` right now, and the parent chain end is + // determined by checking for `parent(id) == id`. This function should return `None` + // for the crate root instead. Some(self.tcx.hir_owner_parent(id.owner)) } else { let owner = self.tcx.hir_owner_nodes(id.owner); - let node = owner.nodes[id.local_id].as_ref()?; + let node = &owner.nodes[id.local_id]; let hir_id = HirId { owner: id.owner, local_id: node.parent }; // HIR indexing should have checked that. debug_assert_ne!(id.local_id, node.parent); @@ -252,11 +247,12 @@ impl<'hir> Map<'hir> { } pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> { - self.tcx.opt_hir_node(self.opt_parent_id(hir_id)?) + Some(self.tcx.hir_node(self.opt_parent_id(hir_id)?)) } pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> { - id.as_local().and_then(|id| self.tcx.opt_hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?)) + id.as_local() + .and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?))) } pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> { @@ -285,20 +281,12 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> { - if let Some(node) = self.tcx.opt_hir_node(hir_id) { - node.fn_decl() - } else { - bug!("no node for hir_id `{}`", hir_id) - } + self.tcx.hir_node(hir_id).fn_decl() } #[track_caller] pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> { - if let Some(node) = self.tcx.opt_hir_node(hir_id) { - node.fn_sig() - } else { - bug!("no node for hir_id `{}`", hir_id) - } + self.tcx.hir_node(hir_id).fn_sig() } #[track_caller] @@ -317,10 +305,7 @@ impl<'hir> Map<'hir> { /// item (possibly associated), a closure, or a `hir::AnonConst`. pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId { let parent = self.parent_id(hir_id); - assert!( - self.tcx.opt_hir_node(parent).is_some_and(|n| is_body_owner(n, hir_id)), - "{hir_id:?}" - ); + assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}"); parent } @@ -572,7 +557,7 @@ impl<'hir> Map<'hir> { /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] pub fn parent_iter(self, current_id: HirId) -> impl Iterator<Item = (HirId, Node<'hir>)> { - self.parent_id_iter(current_id).filter_map(move |id| Some((id, self.tcx.opt_hir_node(id)?))) + self.parent_id_iter(current_id).map(move |id| (id, self.tcx.hir_node(id))) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` @@ -624,7 +609,7 @@ impl<'hir> Map<'hir> { pub fn get_return_block(self, id: HirId) -> Option<HirId> { let mut iter = self.parent_iter(id).peekable(); let mut ignore_tail = false; - if let Some(Node::Expr(Expr { kind: ExprKind::Ret(_), .. })) = self.tcx.opt_hir_node(id) { + if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) { // When dealing with `return` statements, we don't care about climbing only tail // expressions. ignore_tail = true; @@ -777,8 +762,8 @@ impl<'hir> Map<'hir> { } pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> { - match self.tcx.opt_hir_node(id) { - Some(Node::Variant(variant)) => variant, + match self.tcx.hir_node(id) { + Node::Variant(variant) => variant, _ => bug!("expected variant, found {}", self.node_to_string(id)), } } @@ -796,18 +781,18 @@ impl<'hir> Map<'hir> { } pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { - match self.tcx.opt_hir_node(id) { - Some(Node::Expr(expr)) => expr, + match self.tcx.hir_node(id) { + Node::Expr(expr) => expr, _ => bug!("expected expr, found {}", self.node_to_string(id)), } } #[inline] fn opt_ident(self, id: HirId) -> Option<Ident> { - match self.tcx.opt_hir_node(id)? { + match self.tcx.hir_node(id) { Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), // A `Ctor` doesn't have an identifier itself, but its parent - // struct/variant does. Compare with `hir::Map::opt_span`. + // struct/variant does. Compare with `hir::Map::span`. Node::Ctor(..) => match self.find_parent(id)? { Node::Item(item) => Some(item.ident), Node::Variant(variant) => Some(variant.ident), @@ -845,11 +830,6 @@ impl<'hir> Map<'hir> { /// Gets the span of the definition of the specified HIR node. /// This is used by `tcx.def_span`. pub fn span(self, hir_id: HirId) -> Span { - self.opt_span(hir_id) - .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id)) - } - - pub fn opt_span(self, hir_id: HirId) -> Option<Span> { fn until_within(outer: Span, end: Span) -> Span { if let Some(end) = end.find_ancestor_inside(outer) { outer.with_hi(end.hi()) @@ -873,7 +853,7 @@ impl<'hir> Map<'hir> { } } - let span = match self.tcx.opt_hir_node(hir_id)? { + let span = match self.tcx.hir_node(hir_id) { // Function-like. Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. }) | Node::TraitItem(TraitItem { @@ -945,7 +925,7 @@ impl<'hir> Map<'hir> { ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), _ => named_span(item.span, item.ident, None), }, - Node::Ctor(_) => return self.opt_span(self.parent_id(hir_id)), + Node::Ctor(_) => return self.span(self.parent_id(hir_id)), Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), span, @@ -957,7 +937,7 @@ impl<'hir> Map<'hir> { _ => self.span_with_body(hir_id), }; debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt()); - Some(span) + span } /// Like `hir.span()`, but includes the body of items @@ -994,6 +974,9 @@ impl<'hir> Map<'hir> { Node::Infer(i) => i.span, Node::Local(local) => local.span, Node::Crate(item) => item.spans.inner_span, + Node::WhereBoundPredicate(pred) => pred.span, + Node::ArrayLenInfer(inf) => inf.span, + Node::Err(span) => *span, } } @@ -1057,8 +1040,8 @@ impl<'hir> Map<'hir> { } impl<'hir> intravisit::Map<'hir> for Map<'hir> { - fn find(&self, hir_id: HirId) -> Option<Node<'hir>> { - self.tcx.opt_hir_node(hir_id) + fn hir_node(&self, hir_id: HirId) -> Node<'hir> { + self.tcx.hir_node(hir_id) } fn body(&self, id: BodyId) -> &'hir Body<'hir> { @@ -1175,8 +1158,8 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default(); let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str()); - match map.tcx.opt_hir_node(id) { - Some(Node::Item(item)) => { + match map.tcx.hir_node(id) { + Node::Item(item) => { let item_str = match item.kind { ItemKind::ExternCrate(..) => "extern crate", ItemKind::Use(..) => "use", @@ -1204,10 +1187,10 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { }; format!("{id} ({item_str} {})", path_str(item.owner_id.def_id)) } - Some(Node::ForeignItem(item)) => { + Node::ForeignItem(item) => { format!("{id} (foreign item {})", path_str(item.owner_id.def_id)) } - Some(Node::ImplItem(ii)) => { + Node::ImplItem(ii) => { let kind = match ii.kind { ImplItemKind::Const(..) => "assoc const", ImplItemKind::Fn(..) => "method", @@ -1215,7 +1198,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { }; format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id)) } - Some(Node::TraitItem(ti)) => { + Node::TraitItem(ti) => { let kind = match ti.kind { TraitItemKind::Const(..) => "assoc constant", TraitItemKind::Fn(..) => "trait method", @@ -1224,38 +1207,40 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id)) } - Some(Node::Variant(variant)) => { + Node::Variant(variant) => { format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id)) } - Some(Node::Field(field)) => { + Node::Field(field) => { format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) } - Some(Node::AnonConst(_)) => node_str("const"), - Some(Node::ConstBlock(_)) => node_str("const"), - Some(Node::Expr(_)) => node_str("expr"), - Some(Node::ExprField(_)) => node_str("expr field"), - Some(Node::Stmt(_)) => node_str("stmt"), - Some(Node::PathSegment(_)) => node_str("path segment"), - Some(Node::Ty(_)) => node_str("type"), - Some(Node::TypeBinding(_)) => node_str("type binding"), - Some(Node::TraitRef(_)) => node_str("trait ref"), - Some(Node::Pat(_)) => node_str("pat"), - Some(Node::PatField(_)) => node_str("pattern field"), - Some(Node::Param(_)) => node_str("param"), - Some(Node::Arm(_)) => node_str("arm"), - Some(Node::Block(_)) => node_str("block"), - Some(Node::Infer(_)) => node_str("infer"), - Some(Node::Local(_)) => node_str("local"), - Some(Node::Ctor(ctor)) => format!( + Node::AnonConst(_) => node_str("const"), + Node::ConstBlock(_) => node_str("const"), + Node::Expr(_) => node_str("expr"), + Node::ExprField(_) => node_str("expr field"), + Node::Stmt(_) => node_str("stmt"), + Node::PathSegment(_) => node_str("path segment"), + Node::Ty(_) => node_str("type"), + Node::TypeBinding(_) => node_str("type binding"), + Node::TraitRef(_) => node_str("trait ref"), + Node::Pat(_) => node_str("pat"), + Node::PatField(_) => node_str("pattern field"), + Node::Param(_) => node_str("param"), + Node::Arm(_) => node_str("arm"), + Node::Block(_) => node_str("block"), + Node::Infer(_) => node_str("infer"), + Node::Local(_) => node_str("local"), + Node::Ctor(ctor) => format!( "{id} (ctor {})", ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)), ), - Some(Node::Lifetime(_)) => node_str("lifetime"), - Some(Node::GenericParam(param)) => { + Node::Lifetime(_) => node_str("lifetime"), + Node::GenericParam(param) => { format!("{id} (generic_param {})", path_str(param.def_id)) } - Some(Node::Crate(..)) => String::from("(root_crate)"), - None => format!("{id} (unknown node)"), + Node::Crate(..) => String::from("(root_crate)"), + Node::WhereBoundPredicate(_) => node_str("where bound predicate"), + Node::ArrayLenInfer(_) => node_str("array len infer"), + Node::Err(_) => node_str("error"), } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 94191df30a5..f66cd2370e3 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sync::{try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::*; -use rustc_span::{ErrorGuaranteed, ExpnId, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, ExpnId}; /// Gather the LocalDefId for each item-like within a module, including items contained within /// bodies. The Ids are in visitor order. This is used to partition a pass between modules. @@ -148,10 +148,7 @@ pub fn provide(providers: &mut Providers) { providers.hir_attrs = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; - providers.def_span = |tcx, def_id| { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) - }; + providers.def_span = |tcx, def_id| tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); providers.def_ident_span = |tcx, def_id| { let hir_id = tcx.local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 9f1609a5595..2aaece1060a 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -49,7 +49,7 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] -#![cfg_attr(not(bootstrap), feature(trait_upcasting))] +#![feature(trait_upcasting)] #![feature(try_blocks)] #![feature(decl_macro)] #![feature(extract_if)] @@ -58,8 +58,10 @@ #![feature(const_option)] #![feature(ptr_alignment_type)] #![feature(macro_metavar_expr)] -#![allow(rustc::potential_query_instability)] #![allow(internal_features)] +#![allow(rustc::potential_query_instability)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 6f587fdd53c..b601b465668 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -907,6 +907,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { NullOp::SizeOf => write!(fmt, "SizeOf({t})"), NullOp::AlignOf => write!(fmt, "AlignOf({t})"), NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), + NullOp::DebugAssertions => write!(fmt, "cfg!(debug_assertions)"), } } ThreadLocalRef(did) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ca56e1fd92c..40af453f6ce 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1361,6 +1361,8 @@ pub enum NullOp<'tcx> { AlignOf, /// Returns the offset of a field OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), + /// cfg!(debug_assertions), but expanded in codegen + DebugAssertions, } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 4780042a510..5bc151de659 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -194,6 +194,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { tcx.types.usize } + Rvalue::NullaryOp(NullOp::DebugAssertions, _) => tcx.types.bool, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0fed4ccc62a..e1e5d68148f 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1038,7 +1038,6 @@ impl<'tcx> PatRangeBoundary<'tcx> { a.partial_cmp(&b) } ty::Int(ity) => { - use rustc_middle::ty::layout::IntegerExt; let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size(); let a = size.sign_extend(a) as i128; let b = size.sign_extend(b) as i128; diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index b4054f8ff5e..fd5302dc75b 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -1,46 +1,60 @@ use rustc_data_structures::fx::FxHashSet; -use crate::ty::{PolyTraitRef, TyCtxt}; +use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt}; -/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits. +/// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition. +/// /// This only exists in `rustc_middle` because the more powerful elaborator depends on /// `rustc_infer` for elaborating outlives bounds -- this should only be used for pretty /// printing. +pub fn super_predicates_for_pretty_printing<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ref: PolyTraitRef<'tcx>, +) -> impl Iterator<Item = Clause<'tcx>> { + let clause = trait_ref.to_predicate(tcx); + Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] } +} + +/// Like [`super_predicates_for_pretty_printing`], except it only returns traits and filters out +/// all other [`Clause`]s. pub fn supertraits_for_pretty_printing<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: PolyTraitRef<'tcx>, ) -> impl Iterator<Item = PolyTraitRef<'tcx>> { - Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] } + super_predicates_for_pretty_printing(tcx, trait_ref).filter_map(|clause| { + clause.as_trait_clause().map(|trait_clause| trait_clause.to_poly_trait_ref()) + }) } struct Elaborator<'tcx> { tcx: TyCtxt<'tcx>, - visited: FxHashSet<PolyTraitRef<'tcx>>, - stack: Vec<PolyTraitRef<'tcx>>, + visited: FxHashSet<Clause<'tcx>>, + stack: Vec<Clause<'tcx>>, } impl<'tcx> Elaborator<'tcx> { fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) { - let supertrait_refs = self - .tcx - .super_predicates_of(trait_ref.def_id()) - .predicates - .into_iter() - .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause()) - .map(|t| t.map_bound(|pred| pred.trait_ref)) - .filter(|supertrait_ref| self.visited.insert(*supertrait_ref)); - - self.stack.extend(supertrait_refs); + let super_predicates = + self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( + |&(pred, _)| { + let clause = pred.subst_supertrait(self.tcx, &trait_ref); + self.visited.insert(clause).then_some(clause) + }, + ); + + self.stack.extend(super_predicates); } } impl<'tcx> Iterator for Elaborator<'tcx> { - type Item = PolyTraitRef<'tcx>; + type Item = Clause<'tcx>; - fn next(&mut self) -> Option<PolyTraitRef<'tcx>> { - if let Some(trait_ref) = self.stack.pop() { - self.elaborate(trait_ref); - Some(trait_ref) + fn next(&mut self) -> Option<Clause<'tcx>> { + if let Some(clause) = self.stack.pop() { + if let Some(trait_clause) = clause.as_trait_clause() { + self.elaborate(trait_clause.to_poly_trait_ref()); + } + Some(clause) } else { None } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index a2794a100f1..417f1932c6f 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -55,7 +55,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { fn regions( &mut self, a: ty::Region<'tcx>, - b: ty::Region<'tcx>, + _b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { Ok(a) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c0bfd2380ad..f90703e6184 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,7 +1,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::query::IntoQueryParam; use crate::query::Providers; -use crate::traits::util::supertraits_for_pretty_printing; +use crate::traits::util::{super_predicates_for_pretty_printing, supertraits_for_pretty_printing}; use crate::ty::GenericArgKind; use crate::ty::{ ConstInt, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, @@ -1255,8 +1255,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Generate the main trait ref, including associated types. let mut first = true; - if let Some(principal) = predicates.principal() { - self.wrap_binder(&principal, |principal, cx| { + if let Some(bound_principal) = predicates.principal() { + self.wrap_binder(&bound_principal, |principal, cx| { define_scoped_cx!(cx); p!(print_def_path(principal.def_id, &[])); @@ -1281,19 +1281,53 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, // in order to place the projections inside the `<...>`. if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_cx = Ty::new_fresh(cx.tcx(), 0); - let principal = principal.with_self_ty(cx.tcx(), dummy_cx); + let principal_with_self = + principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); let args = cx .tcx() - .generics_of(principal.def_id) - .own_args_no_defaults(cx.tcx(), principal.args); - - let mut projections: Vec<_> = predicates.projection_bounds().collect(); - projections.sort_by_cached_key(|proj| { - cx.tcx().item_name(proj.item_def_id()).to_string() - }); + .generics_of(principal_with_self.def_id) + .own_args_no_defaults(cx.tcx(), principal_with_self.args); + + let bound_principal_with_self = bound_principal + .with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); + + let super_projections: Vec<_> = + super_predicates_for_pretty_printing(cx.tcx(), bound_principal_with_self) + .filter_map(|clause| clause.as_projection_clause()) + .collect(); + + let mut projections: Vec<_> = predicates + .projection_bounds() + .filter(|&proj| { + // Filter out projections that are implied by the super predicates. + let proj_is_implied = super_projections.iter().any(|&super_proj| { + let super_proj = super_proj.map_bound(|super_proj| { + ty::ExistentialProjection::erase_self_ty(cx.tcx(), super_proj) + }); + + // This function is sometimes called on types with erased and + // anonymized regions, but the super projections can still + // contain named regions. So we erase and anonymize everything + // here to compare the types modulo regions below. + let proj = cx.tcx().erase_regions(proj); + let proj = cx.tcx().anonymize_bound_vars(proj); + let super_proj = cx.tcx().erase_regions(super_proj); + let super_proj = cx.tcx().anonymize_bound_vars(super_proj); + + proj == super_proj + }); + !proj_is_implied + }) + .map(|proj| { + // Skip the binder, because we don't want to print the binder in + // front of the associated item. + proj.skip_binder() + }) + .collect(); + + projections + .sort_by_cached_key(|proj| cx.tcx().item_name(proj.def_id).to_string()); if !args.is_empty() || !projections.is_empty() { p!(generic_delimiters(|cx| { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 927924452f9..f592acd4b6f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1052,6 +1052,7 @@ impl<'tcx, T> Binder<'tcx, T> { where T: TypeVisitable<TyCtxt<'tcx>>, { + // `self.value` is equivalent to `self.skip_binder()` if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } @@ -1312,6 +1313,7 @@ impl<'tcx> PolyFnSig<'tcx> { self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs()) } #[inline] + #[track_caller] pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) } @@ -2277,12 +2279,12 @@ impl<'tcx> Ty<'tcx> { } /// Returns the type of metadata for (potentially fat) pointers to this type, - /// and a boolean signifying if this is conditional on this type being `Sized`. - pub fn ptr_metadata_ty( + /// or the struct tail if the metadata type cannot be determined. + pub fn ptr_metadata_ty_or_tail( self, tcx: TyCtxt<'tcx>, normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, - ) -> (Ty<'tcx>, bool) { + ) -> Result<Ty<'tcx>, Ty<'tcx>> { let tail = tcx.struct_tail_with_normalize(self, normalize, || {}); match tail.kind() { // Sized types @@ -2305,31 +2307,47 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) // Extern types have metadata = (). | ty::Foreign(..) - // `dyn*` has no metadata + // `dyn*` has metadata = (). | ty::Dynamic(_, _, ty::DynStar) - // If returned by `struct_tail_without_normalization` this is a unit struct + // If returned by `struct_tail_with_normalize` this is a unit struct // without any fields, or not a struct, and therefore is Sized. | ty::Adt(..) - // If returned by `struct_tail_without_normalization` this is the empty tuple, + // If returned by `struct_tail_with_normalize` this is the empty tuple, // a.k.a. unit type, which is Sized - | ty::Tuple(..) => (tcx.types.unit, false), + | ty::Tuple(..) => Ok(tcx.types.unit), + + ty::Str | ty::Slice(_) => Ok(tcx.types.usize), - ty::Str | ty::Slice(_) => (tcx.types.usize, false), ty::Dynamic(_, _, ty::Dyn) => { let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); - (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false) - }, + Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()])) + } - // type parameters only have unit metadata if they're sized, so return true - // to make sure we double check this during confirmation - ty::Param(_) | ty::Alias(..) => (tcx.types.unit, true), + // We don't know the metadata of `self`, but it must be equal to the + // metadata of `tail`. + ty::Param(_) | ty::Alias(..) => Err(tail), ty::Infer(ty::TyVar(_)) | ty::Bound(..) | ty::Placeholder(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail) - } + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!( + "`ptr_metadata_ty_or_tail` applied to unexpected type: {self:?} (tail = {tail:?})" + ), + } + } + + /// Returns the type of metadata for (potentially fat) pointers to this type. + /// Causes an ICE if the metadata type cannot be determined. + pub fn ptr_metadata_ty( + self, + tcx: TyCtxt<'tcx>, + normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, + ) -> Ty<'tcx> { + match self.ptr_metadata_ty_or_tail(tcx, normalize) { + Ok(metadata) => metadata, + Err(tail) => bug!( + "`ptr_metadata_ty` failed to get metadata for type: {self:?} (tail = {tail:?})" + ), } } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 065c93e86a8..dba8e8b6499 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -40,43 +40,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { - // repeatedly simplify match pairs until fixed point is reached debug!("{candidate:#?}"); - - // existing_bindings and new_bindings exists to keep the semantics in order. - // Reversing the binding order for bindings after `@` changes the binding order in places - // it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)` + // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the + // bindings in `pat` before `x`. E.g. (#69971): + // + // struct NonCopyStruct { + // copy_field: u32, + // } + // + // fn foo1(x: NonCopyStruct) { + // let y @ NonCopyStruct { copy_field: z } = x; + // // the above should turn into + // let z = x.copy_field; + // let y = x; + // } // - // To avoid this, the binding occurs in the following manner: - // * the bindings for one iteration of the following loop occurs in order (i.e. left to - // right) - // * the bindings from the previous iteration of the loop is prepended to the bindings from - // the current iteration (in the implementation this is done by mem::swap and extend) - // * after all iterations, these new bindings are then appended to the bindings that were - // preexisting (i.e. `candidate.binding` when the function was called). + // We can't just reverse the binding order, because we must preserve pattern-order + // otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first, + // and bindings at the same depth stay in source order. + // + // To do this, every time around the loop we prepend the newly found bindings to the + // bindings we already had. // // example: // candidate.bindings = [1, 2, 3] - // binding in iter 1: [4, 5] - // binding in iter 2: [6, 7] + // bindings in iter 1: [4, 5] + // bindings in iter 2: [6, 7] // - // final binding: [1, 2, 3, 6, 7, 4, 5] - let mut existing_bindings = mem::take(&mut candidate.bindings); - let mut new_bindings = Vec::new(); + // final bindings: [6, 7, 4, 5, 1, 2, 3] + let mut accumulated_bindings = mem::take(&mut candidate.bindings); + // Repeatedly simplify match pairs until fixed point is reached loop { - let match_pairs = mem::take(&mut candidate.match_pairs); - - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = - &*match_pairs - { - existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); - return true; - } - let mut changed = false; - for match_pair in match_pairs { + for match_pair in mem::take(&mut candidate.match_pairs) { match self.simplify_match_pair(match_pair, candidate) { Ok(()) => { changed = true; @@ -86,36 +82,39 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } - // Avoid issue #69971: the binding order should be right to left if there are more - // bindings after `@` to please the borrow checker - // Ex - // struct NonCopyStruct { - // copy_field: u32, - // } - // - // fn foo1(x: NonCopyStruct) { - // let y @ NonCopyStruct { copy_field: z } = x; - // // the above should turn into - // let z = x.copy_field; - // let y = x; - // } - candidate.bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut new_bindings); + + // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings + candidate.bindings.extend_from_slice(&accumulated_bindings); + mem::swap(&mut candidate.bindings, &mut accumulated_bindings); candidate.bindings.clear(); if !changed { - existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); - // Move or-patterns to the end, because they can result in us - // creating additional candidates, so we want to test them as - // late as possible. - candidate - .match_pairs - .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); - return false; // if we were not able to simplify any, done. + // If we were not able to simplify anymore, done. + break; } } + + // Store computed bindings back in `candidate`. + mem::swap(&mut candidate.bindings, &mut accumulated_bindings); + + let did_expand_or = + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = + &*candidate.match_pairs + { + candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); + candidate.match_pairs.clear(); + true + } else { + false + }; + + // Move or-patterns to the end, because they can result in us + // creating additional candidates, so we want to test them as + // late as possible. + candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + debug!(simplified = ?candidate, "simplify_candidate"); + + did_expand_or } /// Given `candidate` that has a single or-pattern for its match-pairs, @@ -271,7 +270,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index || { - self.tcx.features().exhaustive_patterns + (self.tcx.features().exhaustive_patterns + || self.tcx.features().min_exhaustive_patterns) && !v .inhabited_predicate(self.tcx, adt_def) .instantiate(self.tcx, args) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9a2f2ceced1..2b1a9fef360 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -666,7 +666,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - let yield_ty = args.yield_ty(); let return_ty = args.return_ty(); ( - vec![closure_ty, args.resume_ty()], + vec![closure_ty, resume_ty], return_ty, Some(Box::new(CoroutineInfo::initial( tcx.coroutine_kind(def_id).unwrap(), @@ -675,8 +675,39 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - ))), ) } - _ => { - span_bug!(span, "expected type of closure body to be a closure or coroutine"); + ty::CoroutineClosure(did, args) => { + let args = args.as_coroutine_closure(); + let sig = tcx.liberate_late_bound_regions( + def_id.to_def_id(), + args.coroutine_closure_sig(), + ); + let self_ty = match args.kind() { + ty::ClosureKind::Fn => { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnMut => { + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, closure_ty) + } + ty::ClosureKind::FnOnce => closure_ty, + }; + ( + [self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()).collect(), + sig.to_coroutine( + tcx, + args.parent_args(), + args.kind_ty(), + tcx.coroutine_for_closure(*did), + Ty::new_error(tcx, guar), + ), + None, + ) + } + ty::Error(_) => (vec![closure_ty, closure_ty], closure_ty, None), + kind => { + span_bug!( + span, + "expected type of closure body to be a closure or coroutine, got {kind:?}" + ); } } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 6827797df37..2d366948771 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -655,7 +655,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let drops = if destination.is_some() { &mut self.scopes.breakable_scopes[break_index].break_drops } else { - self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap() + let Some(drops) = self.scopes.breakable_scopes[break_index].continue_drops.as_mut() + else { + self.tcx.dcx().span_delayed_bug( + source_info.span, + "unlabelled `continue` within labelled block", + ); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + + return self.cfg.start_new_block().unit(); + }; + drops }; let drop_idx = self.scopes.scopes[scope_index + 1..] diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 232b6033946..0bc5fe6ef89 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,7 +2,7 @@ use crate::fluent_generated as fluent; use rustc_errors::DiagnosticArgValue; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessage, + IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -420,10 +420,7 @@ pub struct UnsafeNotInheritedLintNote { } impl AddToDiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); @@ -866,10 +863,7 @@ pub struct Variant { } impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index a3d88b12696..43e44b47e3f 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,6 +1,9 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. + +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 337493d15de..508936be29d 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -72,15 +72,14 @@ pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) && let Some(drop_trait) = tcx.lang_items().drop_trait() && drop_trait == trait_ref.instantiate_identity().def_id + // avoid erroneous `Drop` impls from causing ICEs below + && let sig = tcx.fn_sig(def_id).instantiate_identity() + && sig.inputs().skip_binder().len() == 1 { // It was. Now figure out for what type `Drop` is implemented and then // check for recursion. - if let ty::Ref(_, dropped_ty, _) = tcx - .liberate_late_bound_regions( - def_id.to_def_id(), - tcx.fn_sig(def_id).instantiate_identity().input(0), - ) - .kind() + if let ty::Ref(_, dropped_ty, _) = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() { check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 1156e8be13e..692f4511bb8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -665,7 +665,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // Emit an extra note if the first uncovered witness would be uninhabited // if we disregard visibility. - let witness_1_is_privately_uninhabited = if self.tcx.features().exhaustive_patterns + let witness_1_is_privately_uninhabited = if (self.tcx.features().exhaustive_patterns + || self.tcx.features().min_exhaustive_patterns) && let Some(witness_1) = witnesses.get(0) && let ty::Adt(adt, args) = witness_1.ty().kind() && adt.is_enum() diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 23111cc3199..a4b58e5bfc1 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -4,8 +4,6 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(try_blocks)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 30dd915521c..80e0d0baf57 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -429,7 +429,10 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {} + | Rvalue::NullaryOp( + NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::DebugAssertions, + _, + ) => {} } } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 451d3be255f..ba70a4453d6 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -41,6 +41,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { ty::Closure(..) => Abi::RustCall, ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, + ty::Error(_) => return, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi); diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index f2448ee3d44..04d0a4f303f 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -541,12 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } #[instrument(level = "trace", skip(self), ret)] - fn eval_rvalue( - &mut self, - rvalue: &Rvalue<'tcx>, - location: Location, - dest: &Place<'tcx>, - ) -> Option<()> { + fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<()> { if !dest.projection.is_empty() { return None; } @@ -639,6 +634,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { NullOp::OffsetOf(fields) => { op_layout.offset_of_subfield(self, fields.iter()).bytes() } + NullOp::DebugAssertions => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() } @@ -734,7 +730,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { _ if place.is_indirect() => {} ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => { - if self.eval_rvalue(rvalue, location, place).is_none() { + if self.eval_rvalue(rvalue, place).is_none() { // Const prop failed, so erase the destination, ensuring that whatever happens // from here on, does not know about the previous value. // This is important in case we have diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index fcd4715b9e8..e40f4520671 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir, MirPass}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt}; use rustc_target::abi::FieldIdx; pub struct ByMoveBody; @@ -23,7 +23,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { return; }; let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; - let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!() }; + if coroutine_ty.references_error() { + return; + } + let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); if coroutine_kind == ty::ClosureKind::FnOnce { diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index b0d758bcbfe..663abbece85 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -59,6 +59,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { ty::Closure(..) => Abi::RustCall, ty::CoroutineClosure(..) => Abi::RustCall, ty::Coroutine(..) => Abi::Rust, + ty::Error(_) => return false, _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), }; let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f9798bc4e70..36c441a3945 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -489,6 +489,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { NullOp::OffsetOf(fields) => { layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() } + NullOp::DebugAssertions => return None, }; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); let imm = ImmTy::try_from_uint(val, usize_layout)?; @@ -1231,8 +1232,8 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _: Location) { if let Operand::Move(place) = *operand - && let Some(local) = place.as_local() - && self.reused_locals.contains(local) + && !place.is_indirect_first_projection() + && self.reused_locals.contains(place.local) { *operand = Operand::Copy(place); } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index e77553a03d6..be19bd8349e 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1027,21 +1027,16 @@ fn try_instance_mir<'tcx>( tcx: TyCtxt<'tcx>, instance: InstanceDef<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { - match instance { - ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() { - ty::Adt(def, args) => { - let fields = def.all_fields(); - for field in fields { - let field_ty = field.ty(tcx, args); - if field_ty.has_param() && field_ty.has_projections() { - return Err("cannot build drop shim for polymorphic type"); - } - } - - Ok(tcx.instance_mir(instance)) + if let ty::InstanceDef::DropGlue(_, Some(ty)) = instance + && let ty::Adt(def, args) = ty.kind() + { + let fields = def.all_fields(); + for field in fields { + let field_ty = field.ty(tcx, args); + if field_ty.has_param() && field_ty.has_projections() { + return Err("cannot build drop shim for polymorphic type"); } - _ => Ok(tcx.instance_mir(instance)), - }, - _ => Ok(tcx.instance_mir(instance)), + } } + Ok(tcx.instance_mir(instance)) } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index a28db0defc9..f65eb5cbea9 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -2,10 +2,12 @@ use crate::simplify::simplify_duplicate_switch_targets; use rustc_middle::mir::*; +use rustc_middle::ty::layout; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_target::abi::FieldIdx; +use rustc_target::spec::abi::Abi; pub struct InstSimplify; @@ -38,6 +40,7 @@ impl<'tcx> MirPass<'tcx> for InstSimplify { block.terminator.as_mut().unwrap(), &mut block.statements, ); + ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap()); simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap()); } } @@ -252,6 +255,28 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { terminator.kind = TerminatorKind::Goto { target: destination_block }; } + fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) { + let TerminatorKind::Call { func, unwind, .. } = &mut terminator.kind else { + return; + }; + + let Some((def_id, _)) = func.const_fn_def() else { + return; + }; + + let body_ty = self.tcx.type_of(def_id).skip_binder(); + let body_abi = match body_ty.kind() { + ty::FnDef(..) => body_ty.fn_sig(self.tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Coroutine(..) => Abi::Rust, + _ => bug!("unexpected body ty: {:?}", body_ty), + }; + + if !layout::fn_can_unwind(self.tcx, Some(def_id), body_abi) { + *unwind = UnwindAction::Unreachable; + } + } + fn simplify_intrinsic_assert( &self, terminator: &mut Terminator<'tcx>, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 031515ea958..8e5d69605aa 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(const_type_name)] diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 897375e0e16..f43b85173d4 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -21,6 +21,17 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } + sym::debug_assertions => { + let target = target.unwrap(); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::NullaryOp(NullOp::DebugAssertions, tcx.types.bool), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } sym::forget => { if let Some(target) = *target { block.statements.push(Statement { diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index c00093ea27e..577b8f2080f 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -446,6 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> { NullOp::SizeOf => {} NullOp::AlignOf => {} NullOp::OffsetOf(_) => {} + NullOp::DebugAssertions => {} }, Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b0cfa3568ca..7f36ae91f1a 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,8 +1,6 @@ #![feature(array_windows)] #![feature(is_sorted)] #![allow(rustc::potential_query_instability)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 86a64d90deb..3c3a8d6fbb9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,8 +3,8 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, IntoDiagnostic, Level, - SubdiagnosticMessage, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + IntoDiagnostic, Level, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; @@ -1475,10 +1475,7 @@ pub(crate) struct FnTraitMissingParen { } impl AddToDiagnostic for FnTraitMissingParen { - fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F) - where - F: Fn(&mut rustc_errors::Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); let applicability = if self.machine_applicable { Applicability::MachineApplicable diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index d5fa1108687..5bd8bb72bd6 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,11 +1,13 @@ //! The main parser interface. +#![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] -#![allow(internal_features)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e36a648e203..1a57474bac2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2911,12 +2911,22 @@ impl<'a> Parser<'a> { Ok(arm) => arms.push(arm), Err(e) => { // Recover by skipping to the end of the block. - e.emit(); + let guar = e.emit(); self.recover_stmt(); let span = lo.to(self.token.span); if self.token == token::CloseDelim(Delimiter::Brace) { self.bump(); } + // Always push at least one arm to make the match non-empty + arms.push(Arm { + attrs: Default::default(), + pat: self.mk_pat(span, ast::PatKind::Err(guar)), + guard: None, + body: Some(self.mk_expr_err(span)), + span, + id: DUMMY_NODE_ID, + is_placeholder: false, + }); return Ok(self.mk_expr_with_attrs( span, ExprKind::Match(scrutinee, arms), diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index d76ee161da6..0b65f400825 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -9,8 +9,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] // We want to be able to build this crate with a stable compiler, // so no `#![feature]` attributes should be added. #![deny(unstable_features)] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e652c79d851..ec704dec352 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -827,10 +827,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.doc_attr_str_error(meta, "keyword"); return false; } - match self.tcx.opt_hir_node(hir_id).and_then(|node| match node { + let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, - }) { + }; + match item_kind { Some(ItemKind::Mod(module)) => { if !module.item_ids.is_empty() { self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() }); @@ -853,10 +854,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { - match self.tcx.opt_hir_node(hir_id).and_then(|node| match node { + let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), _ => None, - }) { + }; + match item_kind { Some(ItemKind::Impl(i)) => { let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind { @@ -2221,8 +2223,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } else { // special case when `#[macro_export]` is applied to a macro 2.0 - let (macro_definition, _) = - self.tcx.opt_hir_node(hir_id).unwrap().expect_item().expect_macro(); + let (macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 61c953bcb59..a732bdbca51 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -8,6 +8,7 @@ use rustc_ast::Label; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticSymbolList, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, + SubdiagnosticMessageOp, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -1753,7 +1754,7 @@ pub struct UnusedVariableStringInterp { } impl AddToDiagnostic for UnusedVariableStringInterp { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( crate::fluent_generated::passes_string_interpolation_only_works, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 862b76b1f60..064af5aec35 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -12,8 +12,6 @@ #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(try_blocks)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index f7c382bcd7a..3a8dc377520 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -123,6 +123,7 @@ enum LiveNodeKind { VarDefNode(Span, HirId), ClosureNode, ExitNode, + ErrNode, } fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { @@ -133,6 +134,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)), ClosureNode => "Closure node".to_owned(), ExitNode => "Exit node".to_owned(), + ErrNode => "Error node".to_owned(), } } @@ -967,10 +969,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Now that we know the label we're going to, // look it up in the continue loop nodes table - self.cont_ln - .get(&sc) - .cloned() - .unwrap_or_else(|| span_bug!(expr.span, "continue to unknown label")) + self.cont_ln.get(&sc).cloned().unwrap_or_else(|| { + self.ir.tcx.dcx().span_delayed_bug(expr.span, "continue to unknown label"); + self.ir.add_live_node(ErrNode) + }) } hir::ExprKind::Assign(ref l, ref r, _) => { diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 0f8cc583b03..e10a22cdf31 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -134,7 +134,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { Err(hir::LoopIdError::UnresolvedLabel) => None, }; - if let Some(Node::Block(_)) = loop_id.and_then(|id| self.tcx.opt_hir_node(id)) { + if let Some(Node::Block(_)) = loop_id.map(|id| self.tcx.hir_node(id)) { return; } @@ -186,7 +186,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { match destination.target_id { Ok(loop_id) => { - if let Node::Block(block) = self.tcx.opt_hir_node(loop_id).unwrap() { + if let Node::Block(block) = self.tcx.hir_node(loop_id) { self.sess.dcx().emit_err(ContinueLabeledBlock { span: e.span, block_span: block.span, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index bdb6cf19eac..2dffdc9846c 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessage}; +use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessageOp}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::Ty; @@ -62,10 +62,7 @@ pub struct Overlap<'tcx> { } impl<'tcx> AddToDiagnostic for Overlap<'tcx> { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { let Overlap { span, range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 1a151e72488..164dc36b679 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -1,5 +1,8 @@ //! Analysis of patterns, notably match exhaustiveness checking. +#![allow(rustc::untranslatable_diagnostic)] +#![allow(rustc::diagnostic_outside_of_impl)] + pub mod constructor; #[cfg(feature = "rustc")] pub mod errors; diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 3f1497540d2..30e775733de 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -10,7 +10,7 @@ use crate::MatchArm; /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned /// in a given column. #[instrument(level = "debug", skip(cx), ret)] -fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>( +fn collect_nonexhaustive_missing_variants<'p, 'tcx>( cx: &RustcMatchCheckCtxt<'p, 'tcx>, column: &PatternColumn<'p, RustcMatchCheckCtxt<'p, 'tcx>>, ) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> { diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 576005b2c7f..80a807b4f27 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1520,11 +1520,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( split_ctors.push(Constructor::Missing); } - // Decide what constructors to report. - let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); - let always_report_all = place.is_scrutinee && !is_integers; - // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". - let report_individual_missing_ctors = always_report_all || !all_missing; + // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top + // level we prefer to list all constructors. + let report_individual_missing_ctors = place.is_scrutinee || !all_missing; // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() => // split_ctors.contains(Missing)`. The converse usually holds except when // `!place_validity.is_known_valid()`. diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 90803c20d43..e7a32771f35 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -16,5 +16,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_ty_utils = { path = "../rustc_ty_utils" } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a37d8822480..6d8e7ba937e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -5,8 +5,6 @@ #![feature(associated_type_defaults)] #![feature(try_blocks)] #![feature(let_chains)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -21,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, PatKind}; +use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind}; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; use rustc_middle::ty::GenericArgs; @@ -98,9 +96,6 @@ trait DefIdVisitor<'tcx> { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> { self.skeleton().visit_trait(trait_ref) } - fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<Self::BreakTy> { - self.skeleton().visit_projection_ty(projection) - } fn visit_predicates( &mut self, predicates: ty::GenericPredicates<'tcx>, @@ -173,6 +168,10 @@ where { type BreakTy = V::BreakTy; + fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { + self.visit_clause(p.as_clause().unwrap()) + } + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> { let tcx = self.def_id_visitor.tcx(); // GenericArgs are not visited here because they are visited below @@ -1076,6 +1075,14 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { } } +impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> { + type BreakTy = (); + fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<()> { + self.span = span; + value.visit_with(&mut self.skeleton()) + } +} + impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { fn visit_nested_body(&mut self, body_id: hir::BodyId) { let old_maybe_typeck_results = @@ -1086,18 +1093,15 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { self.span = hir_ty.span; - if let Some(typeck_results) = self.maybe_typeck_results { - // Types in bodies. - if self.visit(typeck_results.node_type(hir_ty.hir_id)).is_break() { - return; - } - } else { - // Types in signatures. - // FIXME: This is very ineffective. Ideally each HIR type should be converted - // into a semantic type only once and the result should be cached somehow. - if self.visit(rustc_hir_analysis::hir_ty_to_ty(self.tcx, hir_ty)).is_break() { - return; - } + if self + .visit( + self.maybe_typeck_results + .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body")) + .node_type(hir_ty.hir_id), + ) + .is_break() + { + return; } intravisit::walk_ty(self, hir_ty); @@ -1105,56 +1109,20 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { self.span = inf.span; - if let Some(typeck_results) = self.maybe_typeck_results { - if let Some(ty) = typeck_results.node_type_opt(inf.hir_id) { - if self.visit(ty).is_break() { - return; - } - } else { - // FIXME: check types of const infers here. + if let Some(ty) = self + .maybe_typeck_results + .unwrap_or_else(|| span_bug!(inf.span, "`hir::InferArg` outside of a body")) + .node_type_opt(inf.hir_id) + { + if self.visit(ty).is_break() { + return; } } else { - span_bug!(self.span, "`hir::InferArg` outside of a body"); + // FIXME: check types of const infers here. } intravisit::walk_inf(self, inf); } - fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) { - self.span = trait_ref.path.span; - if self.maybe_typeck_results.is_some() { - // Privacy of traits in bodies is checked as a part of trait object types. - } else { - let bounds = rustc_hir_analysis::hir_trait_to_predicates( - self.tcx, - trait_ref, - // NOTE: This isn't really right, but the actual type doesn't matter here. It's - // just required by `ty::TraitRef`. - self.tcx.types.never, - ); - - for (clause, _) in bounds.clauses() { - match clause.kind().skip_binder() { - ty::ClauseKind::Trait(trait_predicate) => { - if self.visit_trait(trait_predicate.trait_ref).is_break() { - return; - } - } - ty::ClauseKind::Projection(proj_predicate) => { - let term = self.visit(proj_predicate.term); - if term.is_break() - || self.visit_projection_ty(proj_predicate.projection_ty).is_break() - { - return; - } - } - _ => {} - } - } - } - - intravisit::walk_trait_ref(self, trait_ref); - } - // Check types of expressions fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self.check_expr_pat_type(expr.hir_id, expr.span) { @@ -1727,7 +1695,26 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { // inferred types of expressions and patterns. let span = tcx.def_span(module_def_id); let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span }; - tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor); + + let module = tcx.hir_module_items(module_def_id); + for def_id in module.definitions() { + rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor); + + if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id) { + visitor.visit_nested_body(body_id); + } + } + + for id in module.items() { + if let ItemKind::Impl(i) = tcx.hir().item(id).kind { + if let Some(item) = i.of_trait { + let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap(); + let trait_ref = trait_ref.instantiate_identity(); + visitor.span = item.path.span; + visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path()); + } + } + } } fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 818a67a7deb..0fe5b9c664a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -6,8 +6,6 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![allow(rustc::potential_query_instability, unused_parens)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 2faa4876798..b6ac54a9ab5 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -52,7 +52,7 @@ impl From<DepNodeIndex> for QueryInvocationId { } } -pub(crate) struct MarkFrame<'a> { +pub struct MarkFrame<'a> { index: SerializedDepNodeIndex, parent: Option<&'a MarkFrame<'a>>, } @@ -754,7 +754,6 @@ impl<D: Deps> DepGraphData<D> { &self, qcx: Qcx, parent_dep_node_index: SerializedDepNodeIndex, - dep_node: &DepNode, frame: Option<&MarkFrame<'_>>, ) -> Option<()> { let dep_dep_node_color = self.colors.get(parent_dep_node_index); @@ -861,7 +860,7 @@ impl<D: Deps> DepGraphData<D> { let prev_deps = self.previous.edge_targets_from(prev_dep_node_index); for dep_dep_node_index in prev_deps { - self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?; + self.try_mark_parent_green(qcx, dep_dep_node_index, Some(&frame))?; } // If we got here without hitting a `return` that means that all diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 9b66b9a48d9..416f556f57d 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -4,8 +4,6 @@ #![feature(min_specialization)] #![feature(let_chains)] #![allow(rustc::potential_query_instability, internal_features)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f0b5311f1e1..6bd221ff058 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -23,6 +23,7 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; +use rustc_metadata::creader::CStore; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; @@ -1645,7 +1646,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { debug!(?rib.kind); match rib.kind { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder); + let res = self.create_fresh_lifetime(lifetime.ident, binder); self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } @@ -1737,7 +1738,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } #[instrument(level = "debug", skip(self))] - fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes { + fn create_fresh_lifetime(&mut self, ident: Ident, binder: NodeId) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); @@ -1758,7 +1759,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetimes_in_path( &mut self, - path_id: NodeId, partial_res: PartialRes, path: &[Segment], source: PathSource<'_>, @@ -1891,7 +1891,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Group all suggestions into the first record. let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime); for id in node_ids { - let res = self.create_fresh_lifetime(id, ident, binder); + let res = self.create_fresh_lifetime(ident, binder); self.record_lifetime_res( id, res, @@ -3941,7 +3941,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if record_partial_res == RecordPartialRes::Yes { // Avoid recording definition of `A::B` in `<T as A>::B::C`. self.r.record_partial_res(node_id, partial_res); - self.resolve_elided_lifetimes_in_path(node_id, partial_res, path, source, path_span); + self.resolve_elided_lifetimes_in_path(partial_res, path, source, path_span); } partial_res @@ -4547,14 +4547,20 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if let Some(res) = res && let Some(def_id) = res.opt_def_id() && !def_id.is_local() - && self.r.tcx.crate_types().contains(&CrateType::ProcMacro) - && matches!( - self.r.tcx.sess.opts.resolve_doc_links, - ResolveDocLinks::ExportedMetadata - ) { - // Encoding foreign def ids in proc macro crate metadata will ICE. - return None; + if self.r.tcx.crate_types().contains(&CrateType::ProcMacro) + && matches!( + self.r.tcx.sess.opts.resolve_doc_links, + ResolveDocLinks::ExportedMetadata + ) + { + // Encoding foreign def ids in proc macro crate metadata will ICE. + return None; + } + // Doc paths should be resolved speculatively and should not produce any + // diagnostics, but if they are indeed resolved, then we need to keep the + // corresponding crate alive. + CStore::from_tcx_mut(self.r.tcx).set_used_recursively(def_id.krate); } res }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 16dce7e431d..6c0f2b89347 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -17,7 +17,9 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![allow(rustdoc::private_intra_doc_links)] +#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] +#![allow(rustc::untranslatable_diagnostic)] #![allow(internal_features)] #[macro_use] @@ -1629,6 +1631,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.tcx .sess .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate))); + self.crate_loader(|c| c.unload_unused_crates()); }); // Make sure we don't mutate the cstore from here on. diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 9c34aa93957..95833f532f4 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -17,8 +17,6 @@ #![feature(ptr_sub_ptr)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 0d6328fbb07..58e1394c090 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -4,8 +4,6 @@ #![feature(rustc_attrs)] #![feature(map_many_mut)] #![feature(iter_intersperse)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] #[macro_use] diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 41a4edfc03b..501d6f7d304 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -257,6 +257,7 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf( indices.iter().map(|idx| idx.stable(tables)).collect(), ), + DebugAssertions => stable_mir::mir::NullOp::DebugAssertions, } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index bcf04a71ae2..7d95a0bc478 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,8 +17,6 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![deny(rustc::diagnostic_outside_of_impl)] -#![deny(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 362aaca6364..02bb1fde75c 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -91,8 +91,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index bffb3681f13..b19c5b6f28f 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -17,8 +17,6 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(step_trait)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7894f8dd98f..20cd573f46e 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessage, + EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessageOp, }; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; @@ -102,10 +102,7 @@ pub enum AdjustSignatureBorrow { } impl AddToDiagnostic for AdjustSignatureBorrow { - fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { + fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, _: F) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("len", to_borrow.len()); diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 5ec45212bc7..053ecfc681c 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -14,6 +14,8 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![allow(internal_features)] +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 7052fd776b0..81c0cfea85a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -8,7 +8,7 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Reveal; use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::{ - CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult, + CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult, }; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; @@ -276,25 +276,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, ) -> Vec<Candidate<'tcx>> { - let dummy_candidate = |this: &mut EvalCtxt<'_, 'tcx>, certainty| { - let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); - let result = this.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(); - let mut dummy_probe = this.inspect.new_probe(); - dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) }); - this.inspect.finish_probe(dummy_probe); - vec![Candidate { source, result }] - }; - let Some(normalized_self_ty) = self.try_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { debug!("overflow while evaluating self type"); - return dummy_candidate(self, Certainty::OVERFLOW); + return self.forced_ambiguity(MaybeCause::Overflow); }; if normalized_self_ty.is_ty_var() { debug!("self type has been normalized to infer"); - return dummy_candidate(self, Certainty::AMBIGUOUS); + return self.forced_ambiguity(MaybeCause::Ambiguity); } let goal = @@ -315,11 +306,26 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_param_env_candidates(goal, &mut candidates); - self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + match self.solver_mode() { + SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates), + SolverMode::Coherence => { + self.assemble_coherence_unknowable_candidates(goal, &mut candidates) + } + } candidates } + fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec<Candidate<'tcx>> { + let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); + let certainty = Certainty::Maybe(cause); + let result = self.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(); + let mut dummy_probe = self.inspect.new_probe(); + dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) }); + self.inspect.finish_probe(dummy_probe); + vec![Candidate { source, result }] + } + #[instrument(level = "debug", skip_all)] fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>( &mut self, @@ -542,7 +548,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let alias_ty = match goal.predicate.self_ty().kind() { + let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { + ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); + }); + } + + /// For some deeply nested `<T>::A::B::C::D` rigid associated type, + /// we should explore the item bounds for all levels, since the + /// `associated_type_bounds` feature means that a parent associated + /// type may carry bounds for a nested associated type. + /// + /// If we have a projection, check that its self type is a rigid projection. + /// If so, continue searching by recursively calling after normalization. + // FIXME: This may recurse infinitely, but I can't seem to trigger it without + // hitting another overflow error something. Add a depth parameter needed later. + fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>( + &mut self, + self_ty: Ty<'tcx>, + goal: Goal<'tcx, G>, + candidates: &mut Vec<Candidate<'tcx>>, + ) { + let (kind, alias_ty) = match *self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -567,13 +593,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Param(_) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Alias(ty::Inherent, _) - | ty::Alias(ty::Weak, _) | ty::Error(_) => return, - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { + bug!("unexpected self type for `{goal:?}`") + } + + ty::Infer(ty::TyVar(_)) => { + // If we hit infer when normalizing the self type of an alias, + // then bail with ambiguity. We should never encounter this on + // the *first* iteration of this recursive function. + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); + } + return; + } + + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Alias(ty::Inherent | ty::Weak, _) => { + unreachable!("Weak and Inherent aliases should have been normalized away already") + } }; for assumption in @@ -581,9 +621,28 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { { match G::consider_alias_bound_candidate(self, goal, assumption) { Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }) + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); + } + Err(NoSolution) => {} + } + } + + if kind != ty::Projection { + return; + } + + match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { + // Recurse on the self type of the projection. + Some(next_self_ty) => { + self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates); + } + // Bail if we overflow when normalizing, adding an ambiguous candidate. + None => { + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) + { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); } - Err(NoSolution) => (), } } } @@ -779,6 +838,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + /// In coherence we have to not only care about all impls we know about, but + /// also consider impls which may get added in a downstream or sibling crate + /// or which an upstream impl may add in a minor release. + /// + /// To do so we add an ambiguous candidate in case such an unknown impl could + /// apply to the current goal. #[instrument(level = "debug", skip_all)] fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>( &mut self, @@ -786,11 +851,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec<Candidate<'tcx>>, ) { let tcx = self.tcx(); - match self.solver_mode() { - SolverMode::Normal => return, - SolverMode::Coherence => {} - }; - let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| { let trait_ref = goal.predicate.trait_ref(tcx); #[derive(Debug)] @@ -820,46 +880,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + /// If there's a where-bound for the current goal, do not use any impl candidates + /// to prove the current goal. Most importantly, if there is a where-bound which does + /// not specify any associated types, we do not allow normalizing the associated type + /// by using an impl, even if it would apply. + /// + /// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/76> + // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how + // to improve this however. However, this should make it fairly straightforward to refine + // the filtering going forward, so it seems alright-ish for now. + fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec<Candidate<'tcx>>, + ) { + let tcx = self.tcx(); + let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = + goal.with(tcx, goal.predicate.trait_ref(tcx)); + let mut trait_candidates_from_env = Vec::new(); + self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); + self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env); + if !trait_candidates_from_env.is_empty() { + let trait_env_result = self.merge_candidates(trait_candidates_from_env); + match trait_env_result.unwrap().value.certainty { + // If proving the trait goal succeeds by using the env, + // we freely drop all impl candidates. + // + // FIXME(@lcnr): It feels like this could easily hide + // a forced ambiguity candidate added earlier. + // This feels dangerous. + Certainty::Yes => { + candidates.retain(|c| match c.source { + CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => false, + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, + }); + } + // If it is still ambiguous we instead just force the whole goal + // to be ambig and wait for inference constraints. See + // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs + Certainty::Maybe(cause) => { + *candidates = self.forced_ambiguity(cause); + } + } + } + } + /// If there are multiple ways to prove a trait or projection goal, we have /// to somehow try to merge the candidates into one. If that fails, we return /// ambiguity. #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_candidates( &mut self, - mut candidates: Vec<Candidate<'tcx>>, + candidates: Vec<Candidate<'tcx>>, ) -> QueryResult<'tcx> { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>(); if let Some(result) = self.try_merge_responses(&responses) { return Ok(result); + } else { + self.flounder(&responses) } - - // We then check whether we should prioritize `ParamEnv` candidates. - // - // Doing so is incomplete and would therefore be unsound during coherence. - match self.solver_mode() { - SolverMode::Coherence => (), - // Prioritize `ParamEnv` candidates only if they do not guide inference. - // - // This is still incomplete as we may add incorrect region bounds. - SolverMode::Normal => { - let param_env_responses = candidates - .iter() - .filter(|c| { - matches!( - c.source, - CandidateSource::ParamEnv(_) | CandidateSource::AliasBound - ) - }) - .map(|c| c.result) - .collect::<Vec<_>>(); - if let Some(result) = self.try_merge_responses(¶m_env_responses) { - // We strongly prefer alias and param-env bounds here, even if they affect inference. - // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11. - return Ok(result); - } - } - } - self.flounder(&responses) } } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index d02578c4846..819b070cf8b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -20,7 +20,7 @@ use crate::solve::EvalCtxt; pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, -) -> Result<Vec<Ty<'tcx>>, NoSolution> { +) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { let tcx = ecx.tcx(); match *ty.kind() { ty::Uint(_) @@ -34,7 +34,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Char => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]), + ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]), ty::Dynamic(..) | ty::Param(..) @@ -47,46 +47,48 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - Ok(vec![element_ty]) + Ok(vec![ty::Binder::dummy(element_ty)]) } - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]), ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().collect()) + Ok(tys.iter().map(ty::Binder::dummy).collect()) } - ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), - ty::CoroutineClosure(_, args) => Ok(vec![args.as_coroutine_closure().tupled_upvars_ty()]), + ty::CoroutineClosure(_, args) => { + Ok(vec![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())]) + } ty::Coroutine(_, args) => { let coroutine_args = args.as_coroutine(); - Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()]) + Ok(vec![ + ty::Binder::dummy(coroutine_args.tupled_upvars_ty()), + ty::Binder::dummy(coroutine_args.witness()), + ]) } ty::CoroutineWitness(def_id, args) => Ok(ecx .tcx() .coroutine_hidden_types(def_id) - .map(|bty| { - ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars( - tcx, - bty.instantiate(tcx, args), - )) - }) + .map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args))) .collect()), // For `PhantomData<T>`, we pass `T`. - ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![args.type_at(0)]), + ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]), - ty::Adt(def, args) => Ok(def.all_fields().map(|f| f.ty(tcx, args)).collect()), + ty::Adt(def, args) => { + Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect()) + } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(vec![tcx.type_of(def_id).instantiate(tcx, args)]) + Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))]) } } } @@ -116,7 +118,7 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>( pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, -) -> Result<Vec<Ty<'tcx>>, NoSolution> { +) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { match *ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) @@ -150,11 +152,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( bug!("unexpected type `{ty}`") } - ty::Tuple(tys) => Ok(tys.to_vec()), + ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), ty::Adt(def, args) => { let sized_crit = def.sized_constraint(ecx.tcx()); - Ok(sized_crit.iter_instantiated(ecx.tcx(), args).collect()) + Ok(sized_crit.iter_instantiated(ecx.tcx(), args).map(ty::Binder::dummy).collect()) } } } @@ -163,7 +165,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, -) -> Result<Vec<Ty<'tcx>>, NoSolution> { +) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { match *ty.kind() { ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -194,9 +196,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( bug!("unexpected type `{ty}`") } - ty::Tuple(tys) => Ok(tys.to_vec()), + ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), - ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]), + ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), ty::CoroutineClosure(..) => Err(NoSolution), @@ -205,7 +207,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( Movability::Movable => { if ecx.tcx().features().coroutine_clone { let coroutine = args.as_coroutine(); - Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()]) + Ok(vec![ + ty::Binder::dummy(coroutine.tupled_upvars_ty()), + ty::Binder::dummy(coroutine.witness()), + ]) } else { Err(NoSolution) } @@ -216,10 +221,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( .tcx() .coroutine_hidden_types(def_id) .map(|bty| { - ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars( + replace_erased_lifetimes_with_bound_vars( ecx.tcx(), bty.instantiate(ecx.tcx(), args), - )) + ) }) .collect()), } @@ -318,34 +323,27 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc self_ty: Ty<'tcx>, goal_kind: ty::ClosureKind, env_region: ty::Region<'tcx>, -) -> Result< - (ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option<ty::Predicate<'tcx>>), - NoSolution, -> { +) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution> +{ match *self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); let kind_ty = args.kind_ty(); - - if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + let sig = args.coroutine_closure_sig().skip_binder(); + let mut nested = vec![]; + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { if !closure_kind.extends(goal_kind) { return Err(NoSolution); } - Ok(( - args.coroutine_closure_sig().map_bound(|sig| { - let coroutine_ty = sig.to_coroutine_given_kind_and_upvars( - tcx, - args.parent_args(), - tcx.coroutine_for_closure(def_id), - goal_kind, - env_region, - args.tupled_upvars_ty(), - args.coroutine_captures_by_ref_ty(), - ); - (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) - }), - None, - )) + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + goal_kind, + env_region, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) } else { let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); @@ -362,42 +360,117 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars` // will project to the right upvars for the generator, appending the inputs and // coroutine upvars respecting the closure kind. - Ok(( - args.coroutine_closure_sig().map_bound(|sig| { - let tupled_upvars_ty = Ty::new_projection( - tcx, - upvars_projection_def_id, - [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, goal_kind).into(), - env_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ], - ); - let coroutine_ty = sig.to_coroutine( - tcx, - args.parent_args(), - Ty::from_closure_kind(tcx, goal_kind), - tcx.coroutine_for_closure(def_id), - tupled_upvars_ty, - ); - (sig.tupled_inputs_ty, sig.return_ty, coroutine_ty) - }), - Some( - ty::TraitRef::new( - tcx, - async_fn_kind_trait_def_id, - [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], - ) - .to_predicate(tcx), - ), - )) - } + nested.push( + ty::TraitRef::new( + tcx, + async_fn_kind_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ) + .to_predicate(tcx), + ); + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ) + }; + + Ok(( + args.coroutine_closure_sig().rebind(( + sig.tupled_inputs_ty, + sig.return_ty, + coroutine_ty, + )), + nested, + )) + } + + ty::FnDef(..) | ty::FnPtr(..) => { + let bound_sig = self_ty.fn_sig(tcx); + let sig = bound_sig.skip_binder(); + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + // `FnDef` and `FnPtr` only implement `AsyncFn*` when their + // return type implements `Future`. + let nested = vec![ + bound_sig + .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])) + .to_predicate(tcx), + ]; + let future_output_def_id = tcx + .associated_items(future_trait_def_id) + .filter_by_name_unhygienic(sym::Output) + .next() + .unwrap() + .def_id; + let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); + Ok(( + bound_sig.rebind((Ty::new_tup(tcx, sig.inputs()), sig.output(), future_output_ty)), + nested, + )) } + ty::Closure(_, args) => { + let args = args.as_closure(); + let bound_sig = args.sig(); + let sig = bound_sig.skip_binder(); + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + // `Closure`s only implement `AsyncFn*` when their return type + // implements `Future`. + let mut nested = vec![ + bound_sig + .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])) + .to_predicate(tcx), + ]; + + // Additionally, we need to check that the closure kind + // is still compatible. + let kind_ty = args.kind_ty(); + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + return Err(NoSolution); + } + } else { + let async_fn_kind_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + // When we don't know the closure kind (and therefore also the closure's upvars, + // which are computed at the same time), we must delay the computation of the + // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait + // goal functions similarly to the old `ClosureKind` predicate, and ensures that + // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars` + // will project to the right upvars for the generator, appending the inputs and + // coroutine upvars respecting the closure kind. + nested.push( + ty::TraitRef::new( + tcx, + async_fn_kind_trait_def_id, + [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], + ) + .to_predicate(tcx), + ); + } - ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution), + let future_output_def_id = tcx + .associated_items(future_trait_def_id) + .filter_by_name_unhygienic(sym::Output) + .next() + .unwrap() + .def_id; + let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); + Ok((bound_sig.rebind((sig.inputs()[0], sig.output(), future_output_ty)), nested)) + } ty::Bool | ty::Char diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 76c50a11102..803379af005 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -477,10 +477,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } } else { - let kind = self.infcx.instantiate_binder_with_placeholders(kind); - let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); - self.add_goal(GoalSource::Misc, goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.infcx.enter_forall(kind, |kind| { + let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + self.add_goal(GoalSource::Misc, goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } } @@ -801,13 +802,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) } - pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>( + pub(super) fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( &self, value: ty::Binder<'tcx, T>, - ) -> T { - self.infcx.instantiate_binder_with_placeholders(value) + f: impl FnOnce(T) -> U, + ) -> U { + self.infcx.enter_forall(value, f) } - pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 315df06be41..69b69930432 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -31,103 +31,108 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> { ) -> SelectionResult<'tcx, Selection<'tcx>> { assert!(self.next_trait_solver()); - let trait_goal = Goal::new( - self.tcx, - obligation.param_env, - self.instantiate_binder_with_placeholders(obligation.predicate), - ); - - let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| { - let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate); - let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal); - let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal); - - // pseudo-winnow - if candidates.len() == 0 { - return Err(SelectionError::Unimplemented); - } else if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { - candidate_should_be_dropped_in_favor_of( - ecx.tcx(), - &candidates[i], - &candidates[j], - ) - }); - if should_drop_i { - candidates.swap_remove(i); - } else { - i += 1; - if i > 1 { - return Ok(None); + self.enter_forall(obligation.predicate, |pred| { + let trait_goal = Goal::new(self.tcx, obligation.param_env, pred); + + let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| { + let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate); + let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal); + let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal); + + // pseudo-winnow + if candidates.len() == 0 { + return Err(SelectionError::Unimplemented); + } else if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { + candidate_should_be_dropped_in_favor_of( + ecx.tcx(), + &candidates[i], + &candidates[j], + ) + }); + if should_drop_i { + candidates.swap_remove(i); + } else { + i += 1; + if i > 1 { + return Ok(None); + } } } } - } - let candidate = candidates.pop().unwrap(); - let (certainty, nested_goals) = ecx - .instantiate_and_apply_query_response( - trait_goal.param_env, - orig_values, - candidate.result, - ) - .map_err(|_| SelectionError::Unimplemented)?; - - Ok(Some((candidate, certainty, nested_goals))) - }); - - let (candidate, certainty, nested_goals) = match result { - Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals), - Ok(None) => return Ok(None), - Err(e) => return Err(e), - }; - - let nested_obligations: Vec<_> = nested_goals - .into_iter() - .map(|goal| { - Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate) - }) - .collect(); - - let goal = self.resolve_vars_if_possible(trait_goal); - match (certainty, candidate.source) { - // Rematching the implementation will instantiate the same nested goals that - // would have caused the ambiguity, so we can still make progress here regardless. - (_, CandidateSource::Impl(def_id)) => { - rematch_impl(self, goal, def_id, nested_obligations) - } + let candidate = candidates.pop().unwrap(); + let (certainty, nested_goals) = ecx + .instantiate_and_apply_query_response( + trait_goal.param_env, + orig_values, + candidate.result, + ) + .map_err(|_| SelectionError::Unimplemented)?; + + Ok(Some((candidate, certainty, nested_goals))) + }); + + let (candidate, certainty, nested_goals) = match result { + Ok(Some((candidate, certainty, nested_goals))) => { + (candidate, certainty, nested_goals) + } + Ok(None) => return Ok(None), + Err(e) => return Err(e), + }; + + let nested_obligations: Vec<_> = nested_goals + .into_iter() + .map(|goal| { + Obligation::new( + self.tcx, + ObligationCause::dummy(), + goal.param_env, + goal.predicate, + ) + }) + .collect(); + + let goal = self.resolve_vars_if_possible(trait_goal); + match (certainty, candidate.source) { + // Rematching the implementation will instantiate the same nested goals that + // would have caused the ambiguity, so we can still make progress here regardless. + (_, CandidateSource::Impl(def_id)) => { + rematch_impl(self, goal, def_id, nested_obligations) + } - // If an unsize goal is ambiguous, then we can manually rematch it to make - // selection progress for coercion during HIR typeck. If it is *not* ambiguous, - // but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals, - // and we need to rematch those to detect tuple unsizing and trait upcasting. - // FIXME: This will be wrong if we have param-env or where-clause bounds - // with the unsize goal -- we may need to mark those with different impl - // sources. - (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src)) - | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc)) - if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => - { - rematch_unsize(self, goal, nested_obligations, src, certainty) - } + // If an unsize goal is ambiguous, then we can manually rematch it to make + // selection progress for coercion during HIR typeck. If it is *not* ambiguous, + // but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals, + // and we need to rematch those to detect tuple unsizing and trait upcasting. + // FIXME: This will be wrong if we have param-env or where-clause bounds + // with the unsize goal -- we may need to mark those with different impl + // sources. + (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src)) + | (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc)) + if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => + { + rematch_unsize(self, goal, nested_obligations, src, certainty) + } - // Technically some builtin impls have nested obligations, but if - // `Certainty::Yes`, then they should've all been verified and don't - // need re-checking. - (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => { - Ok(Some(ImplSource::Builtin(src, nested_obligations))) - } + // Technically some builtin impls have nested obligations, but if + // `Certainty::Yes`, then they should've all been verified and don't + // need re-checking. + (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => { + Ok(Some(ImplSource::Builtin(src, nested_obligations))) + } - // It's fine not to do anything to rematch these, since there are no - // nested obligations. - (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { - Ok(Some(ImplSource::Param(nested_obligations))) - } + // It's fine not to do anything to rematch these, since there are no + // nested obligations. + (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { + Ok(Some(ImplSource::Param(nested_obligations))) + } - (Certainty::Maybe(_), _) => Ok(None), - } + (Certainty::Maybe(_), _) => Ok(None), + } + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index f08622816ec..63555a305d8 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -140,7 +140,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { ) } ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( + let (a, b) = infcx.enter_forall_and_leak_universe( goal.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(true, a, b); @@ -150,7 +150,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { ) } ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.instantiate_binder_with_placeholders( + let (a, b) = infcx.enter_forall_and_leak_universe( goal.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(false, a, b); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 6984f0ba694..a7330136fe7 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -124,25 +124,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] - fn compute_closure_kind_goal( - &mut self, - goal: Goal<'tcx, (DefId, ty::GenericArgsRef<'tcx>, ty::ClosureKind)>, - ) -> QueryResult<'tcx> { - let (_, args, expected_kind) = goal.predicate; - let found_kind = args.as_closure().kind_ty().to_opt_closure_kind(); - - let Some(found_kind) = found_kind else { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - }; - if found_kind.extends(expected_kind) { - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - Err(NoSolution) - } - } - - #[instrument(level = "debug", skip(self))] fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { if self.tcx().check_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 47ba549022d..d177109c420 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -491,6 +491,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_misc_candidate("builtin pointee").enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { ty::Bool @@ -522,7 +524,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. + // This is the "fallback impl" for type parameters, unnormalizable projections + // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. + // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't + // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::from_lang_item( tcx, LangItem::Sized, @@ -536,30 +541,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { None => tcx.types.unit, - Some(field_def) => { - let self_ty = field_def.ty(tcx, args); - // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goal( - GoalSource::Misc, - goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)), - ); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + Some(tail_def) => { + let tail_ty = tail_def.ty(tcx, args); + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) } }, ty::Adt(_, _) => tcx.types.unit, ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, - Some(&self_ty) => { - // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goal( - GoalSource::Misc, - goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)), - ); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } + Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), }, ty::Infer( diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index fd09a6b671d..044832224e5 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1049,14 +1049,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn probe_and_evaluate_goal_for_constituent_tys( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>, + constituent_tys: impl Fn( + &EvalCtxt<'_, 'tcx>, + Ty<'tcx>, + ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>, ) -> QueryResult<'tcx> { self.probe_misc_candidate("constituent tys").enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, constituent_tys(ecx, goal.predicate.self_ty())? .into_iter() - .map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))) + .map(|ty| { + ecx.enter_forall(ty, |ty| { + goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)) + }) + }) .collect::<Vec<_>>(), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 4b20de26219..cbe9a238b1c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -971,7 +971,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { let Goal { param_env, predicate } = goal.goal(); - // For bound predicates we simply call `infcx.instantiate_binder_with_placeholders` + // For bound predicates we simply call `infcx.enter_forall` // and then prove the resulting predicate as a nested goal. let trait_ref = match predicate.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index b246e476bed..c6f5af08013 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -21,51 +21,62 @@ pub fn recompute_applicable_impls<'tcx>( let impl_may_apply = |impl_def_id| { let ocx = ObligationCtxt::new(infcx); - let placeholder_obligation = - infcx.instantiate_binder_with_placeholders(obligation.predicate); - let obligation_trait_ref = - ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); - - let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args); - let impl_trait_ref = ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); - - if let Err(_) = - ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) - { - return false; - } + infcx.enter_forall(obligation.predicate, |placeholder_obligation| { + let obligation_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + placeholder_obligation.trait_ref, + ); + + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = + tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args); + let impl_trait_ref = + ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref); + + if let Err(_) = + ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) + { + return false; + } - let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args); - ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { - Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) - })); + let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args); + ocx.register_obligations(impl_predicates.predicates.iter().map(|&predicate| { + Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) + })); - ocx.select_where_possible().is_empty() + ocx.select_where_possible().is_empty() + }) }; let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { let ocx = ObligationCtxt::new(infcx); - let placeholder_obligation = - infcx.instantiate_binder_with_placeholders(obligation.predicate); - let obligation_trait_ref = - ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref); - - let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - poly_trait_predicate, - ); - let param_env_trait_ref = - ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref); - - if let Err(_) = - ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, param_env_trait_ref) - { - return false; - } + infcx.enter_forall(obligation.predicate, |placeholder_obligation| { + let obligation_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + placeholder_obligation.trait_ref, + ); + + let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + poly_trait_predicate, + ); + let param_env_trait_ref = + ocx.normalize(&ObligationCause::dummy(), param_env, param_env_predicate.trait_ref); + + if let Err(_) = ocx.eq( + &ObligationCause::dummy(), + param_env, + obligation_trait_ref, + param_env_trait_ref, + ) { + return false; + } - ocx.select_where_possible().is_empty() + ocx.select_where_possible().is_empty() + }) }; let mut ambiguities = Vec::new(); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 972da180a33..ceff7187646 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -64,39 +64,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> Option<(DefId, GenericArgsRef<'tcx>)> { let tcx = self.tcx; let param_env = obligation.param_env; - let trait_ref = self.instantiate_binder_with_placeholders(trait_ref); - let trait_self_ty = trait_ref.self_ty(); + self.enter_forall(trait_ref, |trait_ref| { + let trait_self_ty = trait_ref.self_ty(); - let mut self_match_impls = vec![]; - let mut fuzzy_match_impls = vec![]; + let mut self_match_impls = vec![]; + let mut fuzzy_match_impls = vec![]; - self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { - let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id); - let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args); + self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { + let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id); + let impl_trait_ref = + tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args); - let impl_self_ty = impl_trait_ref.self_ty(); + let impl_self_ty = impl_trait_ref.self_ty(); - if self.can_eq(param_env, trait_self_ty, impl_self_ty) { - self_match_impls.push((def_id, impl_args)); + if self.can_eq(param_env, trait_self_ty, impl_self_ty) { + self_match_impls.push((def_id, impl_args)); - if iter::zip(trait_ref.args.types().skip(1), impl_trait_ref.args.types().skip(1)) + if iter::zip( + trait_ref.args.types().skip(1), + impl_trait_ref.args.types().skip(1), + ) .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) - { - fuzzy_match_impls.push((def_id, impl_args)); + { + fuzzy_match_impls.push((def_id, impl_args)); + } } - } - }); + }); - let impl_def_id_and_args = if self_match_impls.len() == 1 { - self_match_impls[0] - } else if fuzzy_match_impls.len() == 1 { - fuzzy_match_impls[0] - } else { - return None; - }; + let impl_def_id_and_args = if self_match_impls.len() == 1 { + self_match_impls[0] + } else if fuzzy_match_impls.len() == 1 { + fuzzy_match_impls[0] + } else { + return None; + }; - tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented) - .then_some(impl_def_id_and_args) + tcx.has_attr(impl_def_id_and_args.0, sym::rustc_on_unimplemented) + .then_some(impl_def_id_and_args) + }) } /// Used to set on_unimplemented's `ItemContext` 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 243f583aed8..f68200b6f4d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -19,7 +19,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{Map, Visitor}; +use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; @@ -774,7 +774,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if steps > 0 { // Don't care about `&mut` because `DerefMut` is used less // often and user will not expect that an autoderef happens. - if let Some(hir::Node::Expr(hir::Expr { + if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf( hir::BorrowKind::Ref, @@ -782,7 +782,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expr, ), .. - })) = self.tcx.opt_hir_node(*arg_hir_id) + }) = self.tcx.hir_node(*arg_hir_id) { let derefs = "*".repeat(steps); err.span_suggestion_verbose( @@ -1199,7 +1199,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let Res::Local(hir_id) = path.res else { return; }; - let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(hir_id) else { + let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else { return; }; let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = @@ -1248,52 +1248,55 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - let ty = self.instantiate_binder_with_placeholders(self_ty); - let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { - return false; - }; - let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; - let ty::Param(param) = inner_ty.kind() else { return false }; - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = - obligation.cause.code() - else { - return false; - }; - let arg_node = self.tcx.hir_node(*arg_hir_id); - let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false }; + self.enter_forall(self_ty, |ty: Ty<'_>| { + let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { + return false; + }; + let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; + let ty::Param(param) = inner_ty.kind() else { return false }; + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + else { + return false; + }; + let arg_node = self.tcx.hir_node(*arg_hir_id); + let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { + return false; + }; - let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); - let has_clone = |ty| { - self.type_implements_trait(clone_trait, [ty], obligation.param_env) - .must_apply_modulo_regions() - }; + let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); + let has_clone = |ty| { + self.type_implements_trait(clone_trait, [ty], obligation.param_env) + .must_apply_modulo_regions() + }; - let new_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)), - ); + let new_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)), + ); - if self.predicate_may_hold(&new_obligation) && has_clone(ty) { - if !has_clone(param.to_ty(self.tcx)) { - suggest_constraining_type_param( - self.tcx, - generics, - err, - param.name.as_str(), - "Clone", - Some(clone_trait), - None, + if self.predicate_may_hold(&new_obligation) && has_clone(ty) { + if !has_clone(param.to_ty(self.tcx)) { + suggest_constraining_type_param( + self.tcx, + generics, + err, + param.name.as_str(), + "Clone", + Some(clone_trait), + None, + ); + } + err.span_suggestion_verbose( + obligation.cause.span.shrink_to_hi(), + "consider using clone here", + ".clone()".to_string(), + Applicability::MaybeIncorrect, ); + return true; } - err.span_suggestion_verbose( - obligation.cause.span.shrink_to_hi(), - "consider using clone here", - ".clone()", - Applicability::MaybeIncorrect, - ); - return true; - } - false + false + }) } /// Extracts information about a callable type for diagnostics. This is a @@ -1786,7 +1789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let Res::Local(hir_id) = path.res - && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(hir_id) + && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let None = local.ty && let Some(binding_expr) = local.init @@ -2198,7 +2201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let ty::FnPtr(found) = found.kind() else { return; }; - let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) else { + let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) else { return; }; let hir::ExprKind::Path(path) = arg.kind else { @@ -3186,8 +3189,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::VariableType(hir_id) => { let parent_node = tcx.hir().parent_id(hir_id); - match tcx.opt_hir_node(parent_node) { - Some(Node::Local(hir::Local { ty: Some(ty), .. })) => { + match tcx.hir_node(parent_node) { + Node::Local(hir::Local { ty: Some(ty), .. }) => { err.span_suggestion_verbose( ty.span.shrink_to_lo(), "consider borrowing here", @@ -3196,10 +3199,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); err.note("all local variables must have a statically known size"); } - Some(Node::Local(hir::Local { + Node::Local(hir::Local { init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }), .. - })) => { + }) => { // When encountering an assignment of an unsized trait, like // `let x = ""[..];`, provide a suggestion to borrow the initializer in // order to use have a slice instead. @@ -3211,7 +3214,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); err.note("all local variables must have a statically known size"); } - Some(Node::Param(param)) => { + Node::Param(param) => { err.span_suggestion_verbose( param.ty_span.shrink_to_lo(), "function arguments must have a statically known size, borrowed types \ @@ -3233,7 +3236,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let borrowed_msg = "function arguments must have a statically known size, borrowed \ types always have a known size"; if let Some(hir_id) = hir_id - && let Some(hir::Node::Param(param)) = self.tcx.hir().find(hir_id) + && let hir::Node::Param(param) = self.tcx.hir_node(hir_id) && let Some(item) = self.tcx.hir().find_parent(hir_id) && let Some(decl) = item.fn_decl() && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span)) @@ -3247,7 +3250,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // param._ty_span ty = Some(t); } else if let Some(hir_id) = hir_id - && let Some(hir::Node::Ty(t)) = self.tcx.hir().find(hir_id) + && let hir::Node::Ty(t) = self.tcx.hir_node(hir_id) { ty = Some(t); } @@ -3958,7 +3961,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { call_hir_id: HirId, ) { let tcx = self.tcx; - if let Some(Node::Expr(expr)) = tcx.opt_hir_node(arg_hir_id) + if let Node::Expr(expr) = tcx.hir_node(arg_hir_id) && let Some(typeck_results) = &self.typeck_results { if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr { @@ -4038,26 +4041,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(where_pred) = where_pred.as_trait_clause() && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred() { - let where_pred = self.instantiate_binder_with_placeholders(where_pred); - let failed_pred = self.instantiate_binder_with_fresh_vars( - expr.span, - BoundRegionConversionTime::FnCall, - failed_pred, - ); + self.enter_forall(where_pred, |where_pred| { + let failed_pred = self.instantiate_binder_with_fresh_vars( + expr.span, + BoundRegionConversionTime::FnCall, + failed_pred, + ); - let zipped = iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); - for (expected, actual) in zipped { - self.probe(|_| { - match self.at(&ObligationCause::misc(expr.span, body_id), param_env).eq( - DefineOpaqueTypes::No, - expected, - actual, - ) { - Ok(_) => (), // We ignore nested obligations here for now. - Err(err) => type_diffs.push(err), - } - }) - } + let zipped = + iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); + for (expected, actual) in zipped { + self.probe(|_| { + match self + .at(&ObligationCause::misc(expr.span, body_id), param_env) + .eq(DefineOpaqueTypes::No, expected, actual) + { + Ok(_) => (), // We ignore nested obligations here for now. + Err(err) => type_diffs.push(err), + } + }) + } + }) } else if let Some(where_pred) = where_pred.as_projection_clause() && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() && let Some(found) = failed_pred.skip_binder().term.ty() @@ -4074,9 +4078,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let hir::Path { res: Res::Local(hir_id), .. } = path - && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) + && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) - && let Some(hir::Node::Local(local)) = self.tcx.opt_hir_node(parent_hir_id) + && let hir::Node::Local(local) = self.tcx.hir_node(parent_hir_id) && let Some(binding_expr) = local.init { // If the expression we're calling on is a binding, we want to point at the @@ -4087,17 +4091,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.point_at_chain(expr, typeck_results, type_diffs, param_env, err); } } - let call_node = tcx.opt_hir_node(call_hir_id); - if let Some(Node::Expr(hir::Expr { - kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. - })) = call_node + let call_node = tcx.hir_node(call_hir_id); + if let Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. }) = + call_node { if Some(rcvr.span) == err.span.primary_span() { err.replace_span_with(path.ident.span, true); } } - if let Some(Node::Expr(expr)) = tcx.opt_hir_node(call_hir_id) { + if let Node::Expr(expr) = tcx.hir_node(call_hir_id) { if let hir::ExprKind::Call(hir::Expr { span, .. }, _) | hir::ExprKind::MethodCall( hir::PathSegment { ident: Ident { span, .. }, .. }, @@ -4334,7 +4337,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let hir::Path { res: Res::Local(hir_id), .. } = path - && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) + && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { // We've reached the root of the method call chain... @@ -4615,14 +4618,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { self.probe(|_| { let ocx = ObligationCtxt::new(self); - let pred = self.instantiate_binder_with_placeholders(pred); - let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred); - ocx.register_obligation(Obligation::new( - self.tcx, - ObligationCause::dummy(), - param_env, - pred, - )); + self.enter_forall(pred, |pred| { + let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred); + ocx.register_obligation(Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + pred, + )); + }); if !ocx.select_where_possible().is_empty() { // encountered errors. return; @@ -4769,13 +4773,13 @@ fn hint_missing_borrow<'tcx>( } let found_args = match found.kind() { - ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), + ty::FnPtr(f) => infcx.enter_forall(*f, |f| 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) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(), + ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()), kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 4ef490758a3..07e4fef9dd4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -993,13 +993,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) -> Result<(), ErrorGuaranteed> { if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() - && let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) + && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) && let arg = arg.peel_borrows() && let hir::ExprKind::Path(hir::QPath::Resolved( None, hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) = arg.kind - && let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id) + && let Node::Pat(pat) = self.tcx.hir_node(*hir_id) && let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span) && preds.contains(&obligation.predicate) { @@ -1037,10 +1037,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); - let body_id = match self.tcx.opt_hir_node(hir_id) { - Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { - body_id - } + let body_id = match self.tcx.hir_node(hir_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id, _ => return false, }; let mut v = V { search_span: span, found: None }; @@ -1163,7 +1161,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path - && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) + && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id) && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { // We've reached the root of the method call chain... @@ -1307,12 +1305,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut pred = obligation.predicate.to_opt_poly_trait_pred(); while let Some((next_code, next_pred)) = code.parent() { if let Some(pred) = pred { - let pred = self.instantiate_binder_with_placeholders(pred); - diag.note(format!( - "`{}` must implement `{}`, but it does not", - pred.self_ty(), - pred.print_modifiers_and_trait_path() - )); + self.enter_forall(pred, |pred| { + diag.note(format!( + "`{}` must implement `{}`, but it does not", + pred.self_ty(), + pred.print_modifiers_and_trait_path() + )); + }) } code = next_code; pred = next_pred; @@ -2017,70 +2016,78 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let [single] = &impl_candidates { if self.probe(|_| { let ocx = ObligationCtxt::new(self); - let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref); - let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id); - let impl_trait_ref = ocx.normalize( - &ObligationCause::dummy(), - param_env, - ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args), - ); - ocx.register_obligations( - self.tcx - .predicates_of(single.impl_def_id) - .instantiate(self.tcx, impl_args) - .into_iter() - .map(|(clause, _)| { - Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause) - }), - ); - if !ocx.select_where_possible().is_empty() { - return false; - } + self.enter_forall(trait_ref, |obligation_trait_ref| { + let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id); + let impl_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args), + ); - let mut terrs = vec![]; - for (obligation_arg, impl_arg) in - std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args) - { - if let Err(terr) = - ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg) - { - terrs.push(terr); - } + ocx.register_obligations( + self.tcx + .predicates_of(single.impl_def_id) + .instantiate(self.tcx, impl_args) + .into_iter() + .map(|(clause, _)| { + Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + clause, + ) + }), + ); if !ocx.select_where_possible().is_empty() { return false; } - } - // Literally nothing unified, just give up. - if terrs.len() == impl_trait_ref.args.len() { - return false; - } + let mut terrs = vec![]; + for (obligation_arg, impl_arg) in + std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args) + { + if let Err(terr) = + ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg) + { + terrs.push(terr); + } + if !ocx.select_where_possible().is_empty() { + return false; + } + } - let cand = - self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder { - tcx: self.tcx, - ty_op: |ty| ty, - lt_op: |lt| lt, - ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), - }); - err.highlighted_help(vec![ - StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), - StringPart::highlighted("is"), - StringPart::normal(" implemented for `"), - StringPart::highlighted(cand.self_ty().to_string()), - StringPart::normal("`"), - ]); + // Literally nothing unified, just give up. + if terrs.len() == impl_trait_ref.args.len() { + return false; + } - if let [TypeError::Sorts(exp_found)] = &terrs[..] { - let exp_found = self.resolve_vars_if_possible(*exp_found); - err.help(format!( - "for that trait implementation, expected `{}`, found `{}`", - exp_found.expected, exp_found.found - )); - } + let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with( + &mut BottomUpFolder { + tcx: self.tcx, + ty_op: |ty| ty, + lt_op: |lt| lt, + ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), + }, + ); + err.highlighted_help(vec![ + StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::highlighted("is"), + StringPart::normal(" implemented for `"), + StringPart::highlighted(cand.self_ty().to_string()), + StringPart::normal("`"), + ]); + + if let [TypeError::Sorts(exp_found)] = &terrs[..] { + let exp_found = self.resolve_vars_if_possible(*exp_found); + err.help(format!( + "for that trait implementation, expected `{}`, found `{}`", + exp_found.expected, exp_found.found + )); + } - true + true + }) }) { return true; } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 0337672b302..5ef7a202a12 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -358,8 +358,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) => { - let pred = - ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder)); + let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder)); ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 955c81eee6b..054402acb5c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -40,6 +40,7 @@ use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; +use std::ops::ControlFlow; pub use rustc_middle::traits::Reveal; @@ -250,8 +251,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( let infcx = selcx.infcx; let r = infcx.commit_if_ok(|_snapshot| { let old_universe = infcx.universe(); - let placeholder_predicate = - infcx.instantiate_binder_with_placeholders(obligation.predicate); + let placeholder_predicate = infcx.enter_forall_and_leak_universe(obligation.predicate); let new_universe = infcx.universe(); let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate); @@ -1615,32 +1615,44 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); + let mut ambiguous = false; + selcx.for_each_item_bound( + obligation.predicate.self_ty(), + |selcx, clause, _| { + let Some(clause) = clause.as_projection_clause() else { + return ControlFlow::Continue(()); + }; - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match *obligation.predicate.self_ty().kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ref data) => { - tcx.item_bounds(data.def_id).instantiate(tcx, data.args) - } - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; + let is_match = + selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true)); - assemble_candidates_from_predicates( - selcx, - obligation, - candidate_set, - ProjectionCandidate::TraitDef, - bounds.iter(), - true, + match is_match { + ProjectionMatchesProjection::Yes => { + candidate_set.push_candidate(ProjectionCandidate::TraitDef(clause)); + + if !obligation.predicate.has_non_region_infer() { + // HACK: Pick the first trait def candidate for a fully + // inferred predicate. This is to allow duplicates that + // differ only in normalization. + return ControlFlow::Break(()); + } + } + ProjectionMatchesProjection::Ambiguous => { + candidate_set.mark_ambiguous(); + } + ProjectionMatchesProjection::No => {} + } + + ControlFlow::Continue(()) + }, + // `ProjectionCandidateSet` is borrowed in the above closure, + // so just mark ambiguous outside of the closure. + || ambiguous = true, ); + + if ambiguous { + candidate_set.mark_ambiguous(); + } } /// In the case of a trait object like @@ -1936,10 +1948,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // Integers and floats are always Sized, and so have unit type metadata. | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, - // type parameters, opaques, and unnormalized projections have pointer - // metadata if they're known (e.g. by the param_env) to be sized + // We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able. + // Otherwise, type parameters, opaques, and unnormalized projections have + // unit metadata if they're known (e.g. by the param_env) to be sized. ty::Param(_) | ty::Alias(..) - if selcx.infcx.predicate_must_hold_modulo_regions( + if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions( &obligation.with( selcx.tcx(), ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]), @@ -2074,7 +2087,9 @@ fn confirm_select_candidate<'cx, 'tcx>( } else if lang_items.async_iterator_trait() == Some(trait_def_id) { confirm_async_iterator_candidate(selcx, obligation, data) } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { - if obligation.predicate.self_ty().is_closure() { + if obligation.predicate.self_ty().is_closure() + || obligation.predicate.self_ty().is_coroutine_closure() + { confirm_closure_candidate(selcx, obligation, data) } else { confirm_fn_pointer_candidate(selcx, obligation, data) @@ -2313,7 +2328,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( assert_eq!(metadata_def_id, item_def_id); let mut obligations = Vec::new(); - let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| { + let normalize = |ty| { normalize_with_depth_to( selcx, obligation.param_env, @@ -2322,16 +2337,27 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ty, &mut obligations, ) + }; + let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| { + if tail == self_ty { + // This is the "fallback impl" for type parameters, unnormalizable projections + // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. + // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't + // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`. + let sized_predicate = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + obligation.cause.span(), + [self_ty], + ); + obligations.push(obligation.with(tcx, sized_predicate)); + tcx.types.unit + } else { + // We know that `self_ty` has the same metadata as `tail`. This allows us + // to prove predicates like `Wrapper<Tail>::Metadata == Tail::Metadata`. + Ty::new_projection(tcx, metadata_def_id, [tail]) + } }); - if check_is_sized { - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - obligation.cause.span(), - [self_ty], - ); - obligations.push(obligation.with(tcx, sized_predicate)); - } (metadata_ty.into(), obligations) } else { bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate); @@ -2386,11 +2412,75 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { + let tcx = selcx.tcx(); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); - let ty::Closure(_, args) = self_ty.kind() else { - unreachable!("expected closure self type for closure candidate, found {self_ty}") + let closure_sig = match *self_ty.kind() { + ty::Closure(_, args) => args.as_closure().sig(), + + // Construct a "normal" `FnOnce` signature for coroutine-closure. This is + // basically duplicated with the `AsyncFnOnce::CallOnce` confirmation, but + // I didn't see a good way to unify those. + ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + args.coroutine_closure_sig().map_bound(|sig| { + // If we know the kind and upvars, use that directly. + // Otherwise, defer to `AsyncFnKindHelper::Upvars` to delay + // the projection, like the `AsyncFn*` traits do. + let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() { + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + ty::ClosureKind::FnOnce, + tcx.lifetimes.re_static, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) + } else { + let async_fn_kind_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce).into(), + tcx.lifetimes.re_static.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ) + }; + tcx.mk_fn_sig( + [sig.tupled_inputs_ty], + output_ty, + sig.c_variadic, + sig.unsafety, + sig.abi, + ) + }) + } + + _ => { + unreachable!("expected closure self type for closure candidate, found {self_ty}"); + } }; - let closure_sig = args.as_closure().sig(); + let Normalized { value: closure_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2446,126 +2536,171 @@ fn confirm_callable_candidate<'cx, 'tcx>( fn confirm_async_closure_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - mut nested: Vec<PredicateObligation<'tcx>>, + nested: Vec<PredicateObligation<'tcx>>, ) -> Progress<'tcx> { + let tcx = selcx.tcx(); let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); - let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else { - unreachable!( - "expected coroutine-closure self type for coroutine-closure candidate, found {self_ty}" - ) - }; - let args = args.as_coroutine_closure(); - let kind_ty = args.kind_ty(); - let tcx = selcx.tcx(); let goal_kind = tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap(); - - let async_fn_kind_helper_trait_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - nested.push(obligation.with( - tcx, - ty::TraitRef::new( - tcx, - async_fn_kind_helper_trait_def_id, - [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], - ), - )); - let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2), ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, }; - - let upvars_projection_def_id = tcx - .associated_items(async_fn_kind_helper_trait_def_id) - .filter_by_name_unhygienic(sym::Upvars) - .next() - .unwrap() - .def_id; - - // FIXME(async_closures): Confirmation is kind of a mess here. Ideally, - // we'd short-circuit when we know that the goal_kind >= closure_kind, and not - // register a nested predicate or create a new projection ty here. But I'm too - // lazy to make this more efficient atm, and we can always tweak it later, - // since all this does is make the solver do more work. - // - // The code duplication due to the different length args is kind of weird, too. - // - // See the logic in `structural_traits` in the new solver to understand a bit - // more clearly how this *should* look. - let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| { - let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) { - sym::CallOnceFuture => { - let tupled_upvars_ty = Ty::new_projection( + let item_name = tcx.item_name(obligation.predicate.def_id); + + let poly_cache_entry = match *self_ty.kind() { + ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); + let kind_ty = args.kind_ty(); + let sig = args.coroutine_closure_sig().skip_binder(); + + let term = match item_name { + sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => { + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + bug!("we should not be confirming if the closure kind is not met"); + } + sig.to_coroutine_given_kind_and_upvars( + tcx, + args.parent_args(), + tcx.coroutine_for_closure(def_id), + goal_kind, + env_region, + args.tupled_upvars_ty(), + args.coroutine_captures_by_ref_ty(), + ) + } else { + let async_fn_kind_trait_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + let upvars_projection_def_id = tcx + .associated_items(async_fn_kind_trait_def_id) + .filter_by_name_unhygienic(sym::Upvars) + .next() + .unwrap() + .def_id; + // When we don't know the closure kind (and therefore also the closure's upvars, + // which are computed at the same time), we must delay the computation of the + // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait + // goal functions similarly to the old `ClosureKind` predicate, and ensures that + // the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars` + // will project to the right upvars for the generator, appending the inputs and + // coroutine upvars respecting the closure kind. + // N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`. + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); + sig.to_coroutine( + tcx, + args.parent_args(), + Ty::from_closure_kind(tcx, goal_kind), + tcx.coroutine_for_closure(def_id), + tupled_upvars_ty, + ) + } + } + sym::Output => sig.return_ty, + name => bug!("no such associated type: {name}"), + }; + let projection_ty = match item_name { + sym::CallOnceFuture | sym::Output => ty::AliasTy::new( tcx, - upvars_projection_def_id, - [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, goal_kind).into(), - env_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ], - ); - let coroutine_ty = sig.to_coroutine( + obligation.predicate.def_id, + [self_ty, sig.tupled_inputs_ty], + ), + sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( tcx, - args.parent_args(), - Ty::from_closure_kind(tcx, goal_kind), - tcx.coroutine_for_closure(def_id), - tupled_upvars_ty, - ); - ( - ty::AliasTy::new( - tcx, - obligation.predicate.def_id, - [self_ty, sig.tupled_inputs_ty], - ), - coroutine_ty.into(), - ) - } - sym::CallMutFuture | sym::CallFuture => { - let tupled_upvars_ty = Ty::new_projection( + obligation.predicate.def_id, + [ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()], + ), + name => bug!("no such associated type: {name}"), + }; + + args.coroutine_closure_sig() + .rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }) + } + ty::FnDef(..) | ty::FnPtr(..) => { + let bound_sig = self_ty.fn_sig(tcx); + let sig = bound_sig.skip_binder(); + + let term = match item_name { + sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::Output => { + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_output_def_id = tcx + .associated_items(future_trait_def_id) + .filter_by_name_unhygienic(sym::Output) + .next() + .unwrap() + .def_id; + Ty::new_projection(tcx, future_output_def_id, [sig.output()]) + } + name => bug!("no such associated type: {name}"), + }; + let projection_ty = match item_name { + sym::CallOnceFuture | sym::Output => ty::AliasTy::new( tcx, - upvars_projection_def_id, + obligation.predicate.def_id, + [self_ty, Ty::new_tup(tcx, sig.inputs())], + ), + sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + tcx, + obligation.predicate.def_id, [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, goal_kind).into(), + ty::GenericArg::from(self_ty), + Ty::new_tup(tcx, sig.inputs()).into(), env_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), ], - ); - let coroutine_ty = sig.to_coroutine( + ), + name => bug!("no such associated type: {name}"), + }; + + bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }) + } + ty::Closure(_, args) => { + let args = args.as_closure(); + let bound_sig = args.sig(); + let sig = bound_sig.skip_binder(); + + let term = match item_name { + sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::Output => { + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_output_def_id = tcx + .associated_items(future_trait_def_id) + .filter_by_name_unhygienic(sym::Output) + .next() + .unwrap() + .def_id; + Ty::new_projection(tcx, future_output_def_id, [sig.output()]) + } + name => bug!("no such associated type: {name}"), + }; + let projection_ty = match item_name { + sym::CallOnceFuture | sym::Output => { + ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]]) + } + sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( tcx, - args.parent_args(), - Ty::from_closure_kind(tcx, goal_kind), - tcx.coroutine_for_closure(def_id), - tupled_upvars_ty, - ); - ( - ty::AliasTy::new( - tcx, - obligation.predicate.def_id, - [ - ty::GenericArg::from(self_ty), - sig.tupled_inputs_ty.into(), - env_region.into(), - ], - ), - coroutine_ty.into(), - ) - } - sym::Output => ( - ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]), - sig.return_ty.into(), - ), - name => bug!("no such associated type: {name}"), - }; - ty::ProjectionPredicate { projection_ty, term } - }); + obligation.predicate.def_id, + [ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()], + ), + name => bug!("no such associated type: {name}"), + }; + + bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }) + } + _ => bug!("expected callable type for AsyncFn candidate"), + }; confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true) .with_addl_obligations(nested) 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 4c0c57377e0..a050b30317a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -41,7 +41,28 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// not entirely accurate if inference variables are involved. /// /// This version may conservatively fail when outlives obligations - /// are required. + /// are required. Therefore, this version should only be used for + /// optimizations or diagnostics and be treated as if it can always + /// return `false`. + /// + /// # Example + /// + /// ``` + /// # #![allow(dead_code)] + /// trait Trait {} + /// + /// fn check<T: Trait>() {} + /// + /// fn foo<T: 'static>() + /// where + /// &'static T: Trait, + /// { + /// // Evaluating `&'?0 T: Trait` adds a `'?0: 'static` outlives obligation, + /// // which means that `predicate_must_hold_considering_regions` will return + /// // `false`. + /// check::<&'_ T>(); + /// } + /// ``` fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'tcx>, 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 2258e796103..f9a292c2bd7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,13 +6,16 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use std::ops::ControlFlow; + use hir::def_id::DefId; use hir::LangItem; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -158,11 +161,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, } - let result = self - .infcx - .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); + self.infcx.probe(|_| { + let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let placeholder_trait_predicate = + self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); + debug!(?placeholder_trait_predicate); + + // The bounds returned by `item_bounds` may contain duplicates after + // normalization, so try to deduplicate when possible to avoid + // unnecessary ambiguity. + let mut distinct_normalized_bounds = FxHashSet::default(); + self.for_each_item_bound::<!>( + placeholder_trait_predicate.self_ty(), + |selcx, bound, idx| { + let Some(bound) = bound.as_trait_clause() else { + return ControlFlow::Continue(()); + }; + if bound.polarity() != placeholder_trait_predicate.polarity { + return ControlFlow::Continue(()); + } + + selcx.infcx.probe(|_| { + match selcx.match_normalize_trait_ref( + obligation, + bound.to_poly_trait_ref(), + placeholder_trait_predicate.trait_ref, + ) { + Ok(None) => { + candidates.vec.push(ProjectionCandidate(idx)); + } + Ok(Some(normalized_trait)) + if distinct_normalized_bounds.insert(normalized_trait) => + { + candidates.vec.push(ProjectionCandidate(idx)); + } + _ => {} + } + }); - candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx))); + ControlFlow::Continue(()) + }, + // On ambiguity. + || candidates.ambiguous = true, + ); + }); } /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller @@ -332,6 +374,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + ty::CoroutineClosure(def_id, args) => { + let is_const = self.tcx().is_const_fn_raw(def_id); + match self.infcx.closure_kind(self_ty) { + Some(closure_kind) => { + let no_borrows = match self + .infcx + .shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()) + .kind() + { + ty::Tuple(tys) => tys.is_empty(), + ty::Error(_) => false, + _ => bug!("tuple_fields called on non-tuple"), + }; + // A coroutine-closure implements `FnOnce` *always*, since it may + // always be called once. It additionally implements `Fn`/`FnMut` + // only if it has no upvars (therefore no borrows from the closure + // that would need to be represented with a lifetime) and if the + // closure kind permits it. + // FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut` + // if it takes all of its upvars by copy, and none by ref. This would + // require us to record a bit more information during upvar analysis. + if no_borrows && closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate { is_const }); + } else if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } + } + None => { + if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } else { + // This stays ambiguous until kind+upvars are determined. + candidates.ambiguous = true; + } + } + } + } ty::Infer(ty::TyVar(_)) => { debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); candidates.ambiguous = true; @@ -361,8 +440,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } candidates.vec.push(AsyncClosureCandidate); } - ty::Infer(ty::TyVar(_)) => { - candidates.ambiguous = true; + // Closures and fn pointers implement `AsyncFn*` if their return types + // implement `Future`, which is checked later. + ty::Closure(_, args) => { + if let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind() + && !closure_kind.extends(goal_kind) + { + return; + } + candidates.vec.push(AsyncClosureCandidate); + } + ty::FnDef(..) | ty::FnPtr(..) => { + candidates.vec.push(AsyncClosureCandidate); } _ => {} } @@ -728,64 +817,63 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|_snapshot| { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - let placeholder_trait_predicate = - self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); - - let self_ty = placeholder_trait_predicate.self_ty(); - let principal_trait_ref = match self_ty.kind() { - ty::Dynamic(data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { - debug!( - "assemble_candidates_from_object_ty: matched builtin bound, \ + self.infcx.enter_forall(poly_trait_predicate, |placeholder_trait_predicate| { + let self_ty = placeholder_trait_predicate.self_ty(); + let principal_trait_ref = match self_ty.kind() { + ty::Dynamic(data, ..) => { + if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + debug!( + "assemble_candidates_from_object_ty: matched builtin bound, \ pushing candidate" - ); - candidates.vec.push(BuiltinObjectCandidate); - return; - } + ); + candidates.vec.push(BuiltinObjectCandidate); + return; + } - if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().check_is_object_safe(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) + if let Some(principal) = data.principal() { + if !self.infcx.tcx.features().object_safe_for_dispatch { + principal.with_self_ty(self.tcx(), self_ty) + } else if self.tcx().check_is_object_safe(principal.def_id()) { + principal.with_self_ty(self.tcx(), self_ty) + } else { + return; + } } else { + // Only auto trait bounds exist. return; } - } else { - // Only auto trait bounds exist. + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type return; } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => return, - }; - - debug!(?principal_trait_ref, "assemble_candidates_from_object_ty"); - - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar<i32>`, - // but `Foo` is declared as `trait Foo: Bar<u32>`. - let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref) - .enumerate() - .filter(|&(_, upcast_trait_ref)| { - self.infcx.probe(|_| { - self.match_normalize_trait_ref( - obligation, - upcast_trait_ref, - placeholder_trait_predicate.trait_ref, - ) - .is_ok() + _ => return, + }; + + debug!(?principal_trait_ref, "assemble_candidates_from_object_ty"); + + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar<i32>`, + // but `Foo` is declared as `trait Foo: Bar<u32>`. + let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref) + .enumerate() + .filter(|&(_, upcast_trait_ref)| { + self.infcx.probe(|_| { + self.match_normalize_trait_ref( + obligation, + upcast_trait_ref, + placeholder_trait_predicate.trait_ref, + ) + .is_ok() + }) }) - }) - .map(|(idx, _)| ObjectCandidate(idx)); + .map(|(idx, _)| ObjectCandidate(idx)); - candidates.vec.extend(candidate_supertraits); + candidates.vec.extend(candidate_supertraits); + }) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index c9d06b0f675..6ca24933979 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -159,23 +159,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_predicate = self.infcx.shallow_resolve(obligation.predicate); let placeholder_trait_predicate = - self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref; + self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); - let (def_id, args) = match *placeholder_self_ty.kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), - }; - let candidate_predicate = - tcx.item_bounds(def_id).map_bound(|i| i[idx]).instantiate(tcx, args); + let candidate_predicate = self + .for_each_item_bound( + placeholder_self_ty, + |_, clause, clause_idx| { + if clause_idx == idx { + ControlFlow::Break(clause) + } else { + ControlFlow::Continue(()) + } + }, + || unreachable!(), + ) + .break_value() + .expect("expected to index into clause that exists"); let candidate = candidate_predicate .as_trait_clause() .expect("projection candidate is not a trait predicate") .map_bound(|t| t.trait_ref); + let mut obligations = Vec::new(); let candidate = normalize_with_depth_to( self, @@ -194,8 +200,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented) })?); - if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); + // FIXME(compiler-errors): I don't think this is needed. + if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() { + let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args); for (predicate, _) in predicates { let normalized = normalize_with_depth_to( self, @@ -402,7 +409,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(BuiltinDerivedObligation); let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.instantiate_binder_with_placeholders(poly_trait_ref); + let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations( &cause, obligation.recursion_depth + 1, @@ -493,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); + let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); let ty::Dynamic(data, ..) = *self_ty.kind() else { @@ -691,7 +698,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(BuiltinDerivedObligation); // Confirm the `type Output: Sized;` bound that is present on `FnOnce` - let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output()); + let output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); let output_ty = normalize_with_depth_to( self, obligation.param_env, @@ -712,7 +719,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec<PredicateObligation<'tcx>> { debug!(?obligation, "confirm_trait_alias_candidate"); - let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate); + let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let args = trait_ref.args; @@ -865,17 +872,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let ty::Closure(closure_def_id, args) = *self_ty.kind() else { - bug!("closure candidate for non-closure {:?}", obligation); + let trait_ref = match *self_ty.kind() { + ty::Closure(_, args) => { + self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_) + } + ty::CoroutineClosure(_, args) => { + args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.tupled_inputs_ty], + ) + }) + } + _ => { + bug!("closure candidate for non-closure {:?}", obligation); + } }; - let trait_ref = - self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; - - debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); - - Ok(nested) + self.confirm_poly_trait_refs(obligation, trait_ref) } #[instrument(skip(self), level = "debug")] @@ -883,40 +898,86 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // Okay to skip binder because the args on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters. + let tcx = self.tcx(); let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let ty::CoroutineClosure(closure_def_id, args) = *self_ty.kind() else { - bug!("async closure candidate for non-coroutine-closure {:?}", obligation); - }; - let trait_ref = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { - ty::TraitRef::new( - self.tcx(), - obligation.predicate.def_id(), - [self_ty, sig.tupled_inputs_ty], - ) - }); + let mut nested = vec![]; + let (trait_ref, kind_ty) = match *self_ty.kind() { + ty::CoroutineClosure(_, args) => { + let args = args.as_coroutine_closure(); + let trait_ref = args.coroutine_closure_sig().map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.tupled_inputs_ty], + ) + }); + (trait_ref, args.kind_ty()) + } + ty::FnDef(..) | ty::FnPtr(..) => { + let sig = self_ty.fn_sig(tcx); + let trait_ref = sig.map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, Ty::new_tup(tcx, sig.inputs())], + ) + }); + // We must additionally check that the return type impls `Future`. + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + nested.push(obligation.with( + tcx, + sig.map_bound(|sig| { + ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]) + }), + )); + (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) + } + ty::Closure(_, args) => { + let sig = args.as_closure().sig(); + let trait_ref = sig.map_bound(|sig| { + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.inputs()[0]], + ) + }); + // We must additionally check that the return type impls `Future`. + let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + nested.push(obligation.with( + tcx, + sig.map_bound(|sig| { + ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]) + }), + )); + (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) + } + _ => bug!("expected callable type for AsyncFn candidate"), + }; - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + nested.extend(self.confirm_poly_trait_refs(obligation, trait_ref)?); let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); - nested.push(obligation.with( - self.tcx(), - ty::TraitRef::from_lang_item( + + // If we have not yet determiend the `ClosureKind` of the closure or coroutine-closure, + // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind + // is constrained to an insufficient type later on. + if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() { + if !closure_kind.extends(goal_kind) { + return Err(SelectionError::Unimplemented); + } + } else { + nested.push(obligation.with( self.tcx(), - LangItem::AsyncFnKindHelper, - obligation.cause.span, - [ - args.as_coroutine_closure().kind_ty(), - Ty::from_closure_kind(self.tcx(), goal_kind), - ], - ), - )); - - debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); + ty::TraitRef::from_lang_item( + self.tcx(), + LangItem::AsyncFnKindHelper, + obligation.cause.span, + [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], + ), + )); + } Ok(nested) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7f41c73b72f..ac6cfcdeb59 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -52,6 +52,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::iter; +use std::ops::ControlFlow; pub use rustc_middle::traits::select::*; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -483,7 +484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Instead, we select the right impl now but report "`Bar` does // not implement `Clone`". if candidates.len() == 1 { - return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation); + return self.filter_reservation_impls(candidates.pop().unwrap()); } // Winnow, but record the exact outcome of evaluation, which @@ -557,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Just one candidate left. - self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation) + self.filter_reservation_impls(candidates.pop().unwrap().candidate) } /////////////////////////////////////////////////////////////////////////// @@ -1436,7 +1437,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn filter_reservation_impls( &mut self, candidate: SelectionCandidate<'tcx>, - obligation: &PolyTraitObligation<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { let tcx = self.tcx(); // Treat reservation impls as ambiguity. @@ -1593,71 +1593,41 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate); } - /// Matches a predicate against the bounds of its self type. - /// - /// Given an obligation like `<T as Foo>::Bar: Baz` where the self type is - /// a projection, look at the bounds of `T::Bar`, see if we can find a - /// `Baz` bound. We return indexes into the list returned by - /// `tcx.item_bounds` for any applicable bounds. - #[instrument(level = "debug", skip(self), ret)] - fn match_projection_obligation_against_definition_bounds( + /// Looks at the item bounds of the projection or opaque type. + /// If this is a nested rigid projection, such as + /// `<<T as Tr1>::Assoc as Tr2>::Assoc`, consider the item bounds + /// on both `Tr1::Assoc` and `Tr2::Assoc`, since we may encounter + /// relative bounds on both via the `associated_type_bounds` feature. + pub(super) fn for_each_item_bound<T>( &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> smallvec::SmallVec<[usize; 2]> { - let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - let placeholder_trait_predicate = - self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate); - debug!(?placeholder_trait_predicate); - - let tcx = self.infcx.tcx; - let (def_id, args) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - let bounds = tcx.item_bounds(def_id).instantiate(tcx, args); + mut self_ty: Ty<'tcx>, + mut for_each: impl FnMut(&mut Self, ty::Clause<'tcx>, usize) -> ControlFlow<T, ()>, + on_ambiguity: impl FnOnce(), + ) -> ControlFlow<T, ()> { + let mut idx = 0; + loop { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Infer(ty::TyVar(_)) => { + on_ambiguity(); + return ControlFlow::Continue(()); + } + _ => return ControlFlow::Continue(()), + }; - // The bounds returned by `item_bounds` may contain duplicates after - // normalization, so try to deduplicate when possible to avoid - // unnecessary ambiguity. - let mut distinct_normalized_bounds = FxHashSet::default(); + for bound in + self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + { + for_each(self, bound, idx)?; + idx += 1; + } - bounds - .iter() - .enumerate() - .filter_map(|(idx, bound)| { - let bound_predicate = bound.kind(); - if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() { - let bound = bound_predicate.rebind(pred.trait_ref); - if self.infcx.probe(|_| { - match self.match_normalize_trait_ref( - obligation, - bound, - placeholder_trait_predicate.trait_ref, - ) { - Ok(None) => true, - Ok(Some(normalized_trait)) - if distinct_normalized_bounds.insert(normalized_trait) => - { - true - } - _ => false, - } - }) { - return Some(idx); - } - } - None - }) - .collect() + if kind == ty::Projection { + self_ty = alias_ty.self_ty(); + } else { + return ControlFlow::Continue(()); + } + } } /// Equates the trait in `obligation` with trait bound. If the two traits @@ -2386,7 +2356,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { .flat_map(|ty| { let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ - let placeholder_ty = self.infcx.instantiate_binder_with_placeholders(ty); + let placeholder_ty = self.infcx.enter_forall_and_leak_universe(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -2472,7 +2442,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation: &PolyTraitObligation<'tcx>, ) -> Result<Normalized<'tcx, GenericArgsRef<'tcx>>, ()> { let placeholder_obligation = - self.infcx.instantiate_binder_with_placeholders(obligation.predicate); + self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index c7916ec60bb..e73bbf6048e 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -1,7 +1,5 @@ //! Queries that are independent from the main solver code. -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index c80389a3a4d..ac4f67d1b55 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,8 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(never_type)] #![allow(dead_code, unused_variables)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 9faad10dd14..eae80199ce5 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -278,6 +278,24 @@ fn resolve_associated_item<'tcx>( def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), args: rcvr_args, }), + ty::CoroutineClosure(coroutine_closure_def_id, args) => { + // When a coroutine-closure implements the `Fn` traits, then it + // always dispatches to the `FnOnce` implementation. This is to + // ensure that the `closure_kind` of the resulting closure is in + // sync with the built-in trait implementations (since all of the + // implementations return `FnOnce::Output`). + if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() { + Some(Instance::new(coroutine_closure_def_id, args)) + } else { + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind: ty::ClosureKind::FnOnce, + }, + args, + }) + } + } _ => bug!( "no built-in definition for `{trait_ref}::{}` for non-fn type", tcx.item_name(trait_item_id) @@ -306,6 +324,19 @@ fn resolve_associated_item<'tcx>( Some(Instance::new(coroutine_closure_def_id, args)) } } + ty::Closure(closure_def_id, args) => { + let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); + Some(Instance::resolve_closure( + tcx, + closure_def_id, + args, + trait_closure_kind, + )) + } + ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { + def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + args: rcvr_args, + }), _ => bug!( "no built-in definition for `{trait_ref}::{}` for non-lending-closure type", tcx.item_name(trait_item_id) diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 51acb99d29b..fd392d11e83 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -15,8 +15,6 @@ #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(never_type)] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; @@ -37,7 +35,7 @@ mod layout_sanity_check; mod needs_drop; mod opaque_types; mod representability; -mod sig_types; +pub mod sig_types; mod structural_match; mod ty; diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 3aaa2e73bb8..70f1f099688 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -1,5 +1,3 @@ -#![allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)] - use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_middle::query::Providers; diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index b155a4ac87b..38cc558380c 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -4,11 +4,11 @@ use std::ops::ControlFlow; use rustc_hir::{def::DefKind, def_id::LocalDefId}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; use rustc_type_ir::visit::TypeVisitable; -pub(crate) trait SpannedTypeVisitor<'tcx> { +pub trait SpannedTypeVisitor<'tcx> { type BreakTy = !; fn visit( &mut self, @@ -17,7 +17,7 @@ pub(crate) trait SpannedTypeVisitor<'tcx> { ) -> ControlFlow<Self::BreakTy>; } -pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( +pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( tcx: TyCtxt<'tcx>, item: LocalDefId, visitor: &mut V, @@ -42,11 +42,10 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( DefKind::TyAlias {..} | DefKind::AssocTy | // Walk over the type of the item DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { - let span = match tcx.hir_node_by_def_id(item).ty() { - Some(ty) => ty.span, - _ => tcx.def_span(item), - }; - visitor.visit(span, tcx.type_of(item).instantiate_identity()); + if let Some(ty) = tcx.hir_node_by_def_id(item).ty() { + // Associated types in traits don't necessarily have a type that we can visit + visitor.visit(ty.span, tcx.type_of(item).instantiate_identity())?; + } for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { visitor.visit(span, pred)?; } @@ -59,7 +58,16 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // Look at field types DefKind::Struct | DefKind::Union | DefKind::Enum => { let span = tcx.def_ident_span(item).unwrap(); - visitor.visit(span, tcx.type_of(item).instantiate_identity()); + let ty = tcx.type_of(item).instantiate_identity(); + visitor.visit(span, ty); + let ty::Adt(def, args) = ty.kind() else { + span_bug!(span, "invalid type for {kind:?}: {:#?}", ty.kind()) + }; + for field in def.all_fields() { + let span = tcx.def_ident_span(field.did).unwrap(); + let ty = field.ty(tcx, args); + visitor.visit(span, ty); + } for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { visitor.visit(span, pred)?; } @@ -89,7 +97,6 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( } } | DefKind::Variant - | DefKind::ForeignTy | DefKind::TyParam | DefKind::ConstParam | DefKind::Ctor(_, _) @@ -103,6 +110,7 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // These don't have any types. | DefKind::ExternCrate | DefKind::ForeignMod + | DefKind::ForeignTy | DefKind::Macro(_) | DefKind::GlobalAsm | DefKind::Mod diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 83efbfb855f..f498c5531fc 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -2,8 +2,6 @@ feature = "nightly", feature(associated_type_defaults, min_specialization, never_type, rustc_attrs) )] -#![deny(rustc::untranslatable_diagnostic)] -#![deny(rustc::diagnostic_outside_of_impl)] #![allow(rustc::usage_of_ty_tykind)] #![cfg_attr(feature = "nightly", allow(internal_features))] diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 3b5e41e8d85..777c649fabd 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -163,8 +163,7 @@ pub enum RegionKind<I: Interner> { /// A placeholder region -- the higher-ranked version of `ReLateParam`. /// Should not exist outside of type inference. /// - /// Used when instantiating a `forall` binder via - /// `infcx.instantiate_binder_with_placeholders`. + /// Used when instantiating a `forall` binder via `infcx.enter_forall`. RePlaceholder(I::PlaceholderRegion), /// Erased region, used by trait selection, in MIR and during codegen. diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 38877f7a77f..be727f024c6 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -639,6 +639,7 @@ impl Rvalue { Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { Ok(Ty::usize_ty()) } + Rvalue::NullaryOp(NullOp::DebugAssertions, _) => Ok(Ty::bool_ty()), Rvalue::Aggregate(ak, ops) => match *ak { AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), AggregateKind::Tuple => Ok(Ty::new_tuple( @@ -1005,6 +1006,8 @@ pub enum NullOp { AlignOf, /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), + /// cfg!(debug_assertions), but at codegen time + DebugAssertions, } impl Operand { |
