diff options
Diffstat (limited to 'compiler')
34 files changed, 450 insertions, 287 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eb8e92f07ea..7fecf537cfb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1067,6 +1067,15 @@ impl<'hir> LoweringContext<'_, 'hir> { eq_sign_span: Span, assignments: &mut Vec<hir::Stmt<'hir>>, ) -> &'hir hir::Pat<'hir> { + self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments)) + } + + fn destructure_assign_mut( + &mut self, + lhs: &Expr, + eq_sign_span: Span, + assignments: &mut Vec<hir::Stmt<'hir>>, + ) -> hir::Pat<'hir> { match &lhs.kind { // Underscore pattern. ExprKind::Underscore => { @@ -1080,7 +1089,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (before, after) = pats.split_at(i); hir::PatKind::Slice( before, - Some(self.pat_without_dbm(span, hir::PatKind::Wild)), + Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))), after, ) } else { @@ -1165,14 +1174,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let tuple_pat = hir::PatKind::Tuple(&[], Some(0)); return self.pat_without_dbm(lhs.span, tuple_pat); } else { - return self.destructure_assign(e, eq_sign_span, assignments); + return self.destructure_assign_mut(e, eq_sign_span, assignments); } } _ => {} } // Treat all other cases as normal lvalue. let ident = Ident::new(sym::lhs, lhs.span); - let (pat, binding) = self.pat_ident(lhs.span, ident); + let (pat, binding) = self.pat_ident_mut(lhs.span, ident); let ident = self.expr_ident(lhs.span, ident, binding); let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span); let expr = self.expr(lhs.span, assign, ThinVec::new()); @@ -1191,7 +1200,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ctx: &str, eq_sign_span: Span, assignments: &mut Vec<hir::Stmt<'hir>>, - ) -> (&'hir [&'hir hir::Pat<'hir>], Option<(usize, Span)>) { + ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) { let mut rest = None; let elements = self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| { @@ -1204,7 +1213,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } None } else { - Some(self.destructure_assign(e, eq_sign_span, assignments)) + Some(self.destructure_assign_mut(e, eq_sign_span, assignments)) } })); (elements, rest) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b787158c343..a8d6a99cbeb 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2577,21 +2577,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated) } + fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) { + self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated) + } + fn pat_ident_binding_mode( &mut self, span: Span, ident: Ident, bm: hir::BindingAnnotation, ) -> (&'hir hir::Pat<'hir>, hir::HirId) { + let (pat, hir_id) = self.pat_ident_binding_mode_mut(span, ident, bm); + (self.arena.alloc(pat), hir_id) + } + + fn pat_ident_binding_mode_mut( + &mut self, + span: Span, + ident: Ident, + bm: hir::BindingAnnotation, + ) -> (hir::Pat<'hir>, hir::HirId) { let hir_id = self.next_id(); ( - self.arena.alloc(hir::Pat { + hir::Pat { hir_id, kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None), span, default_binding_modes: true, - }), + }, hir_id, ) } @@ -2609,13 +2623,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) } - fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { - self.arena.alloc(hir::Pat { - hir_id: self.next_id(), - kind, - span, - default_binding_modes: false, - }) + fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> { + hir::Pat { hir_id: self.next_id(), kind, span, default_binding_modes: false } } fn ty_path( diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 66e623528f3..d81ddd2c082 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -10,7 +10,11 @@ use rustc_span::symbol::Ident; use rustc_span::{source_map::Spanned, Span}; impl<'a, 'hir> LoweringContext<'a, 'hir> { - crate fn lower_pat(&mut self, mut pattern: &Pat) -> &'hir hir::Pat<'hir> { + crate fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { + self.arena.alloc(self.lower_pat_mut(pattern)) + } + + crate fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion let node = loop { @@ -34,7 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } PatKind::Or(ref pats) => { break hir::PatKind::Or( - self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))), + self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))), ); } PatKind::Path(ref qself, ref path) => { @@ -101,7 +105,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, pats: &[P<Pat>], ctx: &str, - ) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) { + ) -> (&'hir [hir::Pat<'hir>], Option<usize>) { let mut elems = Vec::with_capacity(pats.len()); let mut rest = None; @@ -140,7 +144,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } // It was not a sub-tuple pattern so lower it normally. - elems.push(self.lower_pat(pat)); + elems.push(self.lower_pat_mut(pat)); } for (_, pat) in iter { @@ -149,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ...but there was one again, so error. self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx); } else { - elems.push(self.lower_pat(pat)); + elems.push(self.lower_pat_mut(pat)); } } @@ -189,11 +193,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Record, lower it to `$binding_mode $ident @ _`, and stop here. PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { prev_rest_span = Some(sub.span); - slice = Some(lower_rest_sub(self, pat, bm, ident, sub)); + slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub))); break; } // It was not a subslice pattern so lower it normally. - _ => before.push(self.lower_pat(pat)), + _ => before.push(self.lower_pat_mut(pat)), } } @@ -214,7 +218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice"); } else { // Lower the pattern normally. - after.push(self.lower_pat(pat)); + after.push(self.lower_pat_mut(pat)); } } @@ -268,17 +272,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - self.pat_with_node_id_of(p, hir::PatKind::Wild) + self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild)) } /// Construct a `Pat` with the `HirId` of `p.id` lowered. - fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> { - self.arena.alloc(hir::Pat { + fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> { + hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span, default_binding_modes: true, - }) + } } /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern. diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs index 73b04d3329c..1786fa340cc 100644 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ b/compiler/rustc_data_structures/src/vec_map.rs @@ -127,13 +127,15 @@ impl<K, V> IntoIterator for VecMap<K, V> { } } -impl<K, V> Extend<(K, V)> for VecMap<K, V> { +impl<K: PartialEq, V> Extend<(K, V)> for VecMap<K, V> { fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { - self.0.extend(iter); + for (k, v) in iter { + self.insert(k, v); + } } - fn extend_one(&mut self, item: (K, V)) { - self.0.extend_one(item); + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); } fn extend_reserve(&mut self, additional: usize) { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ede510b6936..15123b5b28d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -405,7 +405,7 @@ declare_features! ( (active, in_band_lifetimes, "1.23.0", Some(44524), None), /// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598). - (incomplete, generic_associated_types, "1.23.0", Some(44265), None), + (active, generic_associated_types, "1.23.0", Some(44265), None), /// Allows defining `trait X = A + B;` alias items. (active, trait_alias, "1.24.0", Some(41517), None), @@ -534,7 +534,7 @@ declare_features! ( (active, bindings_after_at, "1.41.0", Some(65490), None), /// Allows `impl const Trait for T` syntax. - (incomplete, const_trait_impl, "1.42.0", Some(67792), None), + (active, const_trait_impl, "1.42.0", Some(67792), None), /// Allows `T: ?const Trait` syntax in bounds. (incomplete, const_trait_bound_opt_out, "1.42.0", Some(67794), None), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7ce92ea579..4b2679e164a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -808,13 +808,13 @@ impl<'hir> Pat<'hir> { } use PatKind::*; - match &self.kind { + match self.kind { Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), Slice(before, slice, after) => { - before.iter().chain(slice.iter()).chain(after.iter()).all(|p| p.walk_short_(it)) + before.iter().chain(slice).chain(after.iter()).all(|p| p.walk_short_(it)) } } } @@ -836,13 +836,13 @@ impl<'hir> Pat<'hir> { } use PatKind::*; - match &self.kind { + match self.kind { Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), Slice(before, slice, after) => { - before.iter().chain(slice.iter()).chain(after.iter()).for_each(|p| p.walk_(it)) + before.iter().chain(slice).chain(after.iter()).for_each(|p| p.walk_(it)) } } } @@ -940,11 +940,11 @@ pub enum PatKind<'hir> { /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. /// `0 <= position <= subpats.len()` - TupleStruct(QPath<'hir>, &'hir [&'hir Pat<'hir>], Option<usize>), + TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. - Or(&'hir [&'hir Pat<'hir>]), + Or(&'hir [Pat<'hir>]), /// A path pattern for an unit struct/variant or a (maybe-associated) constant. Path(QPath<'hir>), @@ -952,7 +952,7 @@ pub enum PatKind<'hir> { /// A tuple pattern (e.g., `(a, b)`). /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position. /// `0 <= position <= subpats.len()` - Tuple(&'hir [&'hir Pat<'hir>], Option<usize>), + Tuple(&'hir [Pat<'hir>], Option<usize>), /// A `box` pattern. Box(&'hir Pat<'hir>), @@ -975,7 +975,7 @@ pub enum PatKind<'hir> { /// ``` /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)]) /// ``` - Slice(&'hir [&'hir Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [&'hir Pat<'hir>]), + Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]), } #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)] diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a33234a91fa..d5c17ede214 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -70,6 +70,10 @@ pub struct FulfillmentError<'tcx> { /// obligation error caused by a call argument. When this is the case, we also signal that in /// this field to ensure accuracy of suggestions. pub points_at_arg_span: bool, + /// Diagnostics only: the 'root' obligation which resulted in + /// the failure to process `obligation`. This is the obligation + /// that was initially passed to `register_predicate_obligation` + pub root_obligation: PredicateObligation<'tcx>, } #[derive(Clone)] @@ -122,8 +126,9 @@ impl<'tcx> FulfillmentError<'tcx> { pub fn new( obligation: PredicateObligation<'tcx>, code: FulfillmentErrorCode<'tcx>, + root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation, code, points_at_arg_span: false } + FulfillmentError { obligation, code, points_at_arg_span: false, root_obligation } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 92e627bce02..ccdbccae156 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2315,7 +2315,7 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(generic_associated_types)] + /// #![feature(const_generics)] /// ``` /// /// {{produces}} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 80c4ff2ae5d..1651853a552 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1713,4 +1713,18 @@ rustc_queries! { query limits(key: ()) -> Limits { desc { "looking up limits" } } + + /// Performs an HIR-based well-formed check on the item with the given `HirId`. If + /// we get an `Umimplemented` error that matches the provided `Predicate`, return + /// the cause of the newly created obligation. + /// + /// This is only used by error-reporting code to get a better cause (in particular, a better + /// span) for an *existing* error. Therefore, it is best-effort, and may never handle + /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, + /// because the `ty::Ty`-based wfcheck is always run. + query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option<traits::ObligationCause<'tcx>> { + eval_always + no_hash + desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 } + } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 892a29e4e22..221dac9ca03 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,6 +13,7 @@ use crate::mir::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -24,7 +25,6 @@ use smallvec::SmallVec; use std::borrow::Cow; use std::fmt; use std::ops::Deref; -use std::rc::Rc; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; @@ -87,7 +87,7 @@ pub enum Reveal { #[derive(Clone, PartialEq, Eq, Hash, Lift)] pub struct ObligationCause<'tcx> { /// `None` for `ObligationCause::dummy`, `Some` otherwise. - data: Option<Rc<ObligationCauseData<'tcx>>>, + data: Option<Lrc<ObligationCauseData<'tcx>>>, } const DUMMY_OBLIGATION_CAUSE_DATA: ObligationCauseData<'static> = @@ -131,7 +131,7 @@ impl<'tcx> ObligationCause<'tcx> { body_id: hir::HirId, code: ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { - ObligationCause { data: Some(Rc::new(ObligationCauseData { span, body_id, code })) } + ObligationCause { data: Some(Lrc::new(ObligationCauseData { span, body_id, code })) } } pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { @@ -148,7 +148,7 @@ impl<'tcx> ObligationCause<'tcx> { } pub fn make_mut(&mut self) -> &mut ObligationCauseData<'tcx> { - Rc::make_mut(self.data.get_or_insert_with(|| Rc::new(DUMMY_OBLIGATION_CAUSE_DATA))) + Lrc::make_mut(self.data.get_or_insert_with(|| Lrc::new(DUMMY_OBLIGATION_CAUSE_DATA))) } pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { @@ -326,6 +326,13 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, + + /// Well-formed checking. If a `HirId` is provided, + /// it is used to perform HIR-based wf checking if an error + /// occurs, in order to generate a more precise error message. + /// This is purely for diagnostic purposes - it is always + /// correct to use `MiscObligation` instead + WellFormed(Option<hir::HirId>), } impl ObligationCauseCode<'_> { @@ -389,7 +396,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_trait_ref: ty::PolyTraitRef<'tcx>, /// The parent trait had this cause. - pub parent_code: Rc<ObligationCauseCode<'tcx>>, + pub parent_code: Lrc<ObligationCauseCode<'tcx>>, } #[derive(Clone, Debug, TypeFoldable, Lift)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 42a8f1763f1..bfc942e6f10 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -857,7 +857,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)] pub struct OpaqueTypeKey<'tcx> { pub def_id: DefId, pub substs: SubstsRef<'tcx>, diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index bd951ef72b5..b4fe3313e8a 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -2070,24 +2070,26 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("check_rvalue: is_const_fn={:?}", is_const_fn); let def_id = body.source.def_id().expect_local(); - self.infcx.report_selection_error( - &traits::Obligation::new( - ObligationCause::new( - span, - self.tcx().hir().local_def_id_to_hir_id(def_id), - traits::ObligationCauseCode::RepeatVec(is_const_fn), - ), - self.param_env, - ty::Binder::dummy(ty::TraitRef::new( - self.tcx().require_lang_item( - LangItem::Copy, - Some(self.last_span), - ), - tcx.mk_substs_trait(ty, &[]), - )) - .without_const() - .to_predicate(self.tcx()), + let obligation = traits::Obligation::new( + ObligationCause::new( + span, + self.tcx().hir().local_def_id_to_hir_id(def_id), + traits::ObligationCauseCode::RepeatVec(is_const_fn), ), + self.param_env, + ty::Binder::dummy(ty::TraitRef::new( + self.tcx().require_lang_item( + LangItem::Copy, + Some(self.last_span), + ), + tcx.mk_substs_trait(ty, &[]), + )) + .without_const() + .to_predicate(self.tcx()), + ); + self.infcx.report_selection_error( + obligation.clone(), + &obligation, &traits::SelectionError::Unimplemented, false, false, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3ea76fb99d5..046f4140036 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -325,7 +325,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_tuple_subpats( &mut self, - pats: &'tcx [&'tcx hir::Pat<'tcx>], + pats: &'tcx [hir::Pat<'tcx>], expected_len: usize, gap_pos: Option<usize>, ) -> Vec<FieldPat<'tcx>> { @@ -338,7 +338,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .collect() } - fn lower_patterns(&mut self, pats: &'tcx [&'tcx hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> { + fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec<Pat<'tcx>> { pats.iter().map(|p| self.lower_pattern(p)).collect() } @@ -350,9 +350,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { &mut self, span: Span, ty: Ty<'tcx>, - prefix: &'tcx [&'tcx hir::Pat<'tcx>], + prefix: &'tcx [hir::Pat<'tcx>], slice: &'tcx Option<&'tcx hir::Pat<'tcx>>, - suffix: &'tcx [&'tcx hir::Pat<'tcx>], + suffix: &'tcx [hir::Pat<'tcx>], ) -> PatKind<'tcx> { let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index b3cc7de4662..1993e0a602f 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,6 +1,7 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::HirId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -395,3 +396,14 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { DUMMY_SP } } + +impl<'tcx> Key for (ty::Predicate<'tcx>, HirId) { + #[inline(always)] + fn query_crate_is_local(&self) -> bool { + true + } + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9fc907da265..ea074192d23 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -30,8 +30,7 @@ pub trait InferCtxtExt<'tcx> { fn partially_normalize_associated_types_in<T>( &self, - span: Span, - body_id: hir::HirId, + cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: T, ) -> InferOk<'tcx, T> @@ -79,8 +78,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// new obligations that must further be processed. fn partially_normalize_associated_types_in<T>( &self, - span: Span, - body_id: hir::HirId, + cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: T, ) -> InferOk<'tcx, T> @@ -89,7 +87,6 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { { debug!("partially_normalize_associated_types_in(value={:?})", value); let mut selcx = traits::SelectionContext::new(self); - let cause = ObligationCause::misc(span, body_id); let traits::Normalized { value, obligations } = traits::normalize(&mut selcx, param_env, cause, value); debug!( diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 0061ce4ed37..cc98cd72566 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -1,5 +1,5 @@ use crate::infer::InferCtxtExt as _; -use crate::traits::{self, PredicateObligation}; +use crate::traits::{self, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -568,6 +568,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// - `substs`, the substs used to instantiate this opaque type /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of /// `opaque_defn.concrete_ty` + #[instrument(skip(self))] fn infer_opaque_definition_from_instantiation( &self, opaque_type_key: OpaqueTypeKey<'tcx>, @@ -576,11 +577,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let OpaqueTypeKey { def_id, substs } = opaque_type_key; - debug!( - "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", - def_id, instantiated_ty - ); - // Use substs to build up a reverse map from regions to their // identity mappings. This is necessary because of `impl // Trait` lifetimes are computed by replacing existing @@ -588,6 +584,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // `impl Trait` return type, resulting in the parameters // shifting. let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + debug!(?id_substs); let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); @@ -602,7 +599,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { instantiated_ty, span, )); - debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty); + debug!(?definition_ty); definition_ty } @@ -857,7 +854,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { self.tcx.mk_generator(def_id, substs, movability) } - ty::Param(..) => { + ty::Param(param) => { // Look it up in the substitution list. match self.map.get(&ty.into()).map(|k| k.unpack()) { // Found it in the substitution list; replace with the parameter from the @@ -865,6 +862,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { Some(GenericArgKind::Type(t1)) => t1, Some(u) => panic!("type mapped to unexpected kind: {:?}", u), None => { + debug!(?param, ?self.map); self.tcx .sess .struct_span_err( @@ -931,8 +929,8 @@ struct Instantiator<'a, 'tcx> { } impl<'a, 'tcx> Instantiator<'a, 'tcx> { + #[instrument(skip(self))] fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { - debug!("instantiate_opaque_types_in_map(value={:?})", value); let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { tcx, @@ -1051,8 +1049,11 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect(); let param_env = tcx.param_env(def_id); - let InferOk { value: bounds, obligations } = - infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, bounds); + let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in( + ObligationCause::misc(span, self.body_id), + param_env, + bounds, + ); self.obligations.extend(obligations); debug!("instantiate_opaque_types: bounds={:?}", bounds); diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 026ab414443..7a690af0cc6 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -58,6 +58,9 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { obligation: obligation.clone(), code: FulfillmentErrorCode::CodeAmbiguity, points_at_arg_span: false, + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation.clone(), }) .collect(); Err(errors) @@ -105,11 +108,14 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { ), Err(_err) => errors.push(FulfillmentError { - obligation, + obligation: obligation.clone(), code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, ), points_at_arg_span: false, + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation, }), } } else { @@ -119,11 +125,14 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { } Err(NoSolution) => errors.push(FulfillmentError { - obligation, + obligation: obligation.clone(), code: FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, ), points_at_arg_span: false, + // FIXME - does Chalk have a notation of 'root obligation'? + // This is just for diagnostics, so it's okay if this is wrong + root_obligation: obligation, }), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e276d92bf5a..5c4aef529e5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -55,9 +55,13 @@ pub trait InferCtxtExt<'tcx> { fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; + /// The `root_obligation` parameter should be the `root_obligation` field + /// from a `FulfillmentError`. If no `FulfillmentError` is available, + /// then it should be the same as `obligation`. fn report_selection_error( &self, - obligation: &PredicateObligation<'tcx>, + obligation: PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, fallback_has_occurred: bool, points_at_arg: bool, @@ -225,16 +229,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn report_selection_error( &self, - obligation: &PredicateObligation<'tcx>, + mut obligation: PredicateObligation<'tcx>, + root_obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>, fallback_has_occurred: bool, points_at_arg: bool, ) { let tcx = self.tcx; - let span = obligation.cause.span; + let mut span = obligation.cause.span; let mut err = match *error { SelectionError::Unimplemented => { + // If this obligation was generated as a result of well-formed checking, see if we + // can get a better error message by performing HIR-based well formed checking. + if let ObligationCauseCode::WellFormed(Some(wf_hir_id)) = + root_obligation.cause.code.peel_derives() + { + if let Some(cause) = + self.tcx.diagnostic_hir_wf_check((obligation.predicate, *wf_hir_id)) + { + obligation.cause = cause; + span = obligation.cause.span; + } + } if let ObligationCauseCode::CompareImplMethodObligation { item_name, impl_item_def_id, @@ -279,7 +296,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .unwrap_or_default(); let OnUnimplementedNote { message, label, note, enclosing_scope } = - self.on_unimplemented_note(trait_ref, obligation); + self.on_unimplemented_note(trait_ref, &obligation); let have_alt_message = message.is_some() || label.is_some(); let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); let is_unsize = @@ -338,7 +355,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - if let Some(ret_span) = self.return_type_span(obligation) { + if let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( ret_span, &format!( @@ -368,7 +385,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { points_at_arg, have_alt_message, ) { - self.note_obligation_cause(&mut err, obligation); + self.note_obligation_cause(&mut err, &obligation); err.emit(); return; } @@ -821,7 +838,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }; - self.note_obligation_cause(&mut err, obligation); + self.note_obligation_cause(&mut err, &obligation); self.point_at_returns_when_relevant(&mut err, &obligation); err.emit(); @@ -1168,7 +1185,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( - &error.obligation, + error.obligation.clone(), + &error.root_obligation, selection_error, fallback_has_occurred, error.points_at_arg_span, 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 26a5a65ed36..adeb1d58d1e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1902,7 +1902,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) | ObligationCauseCode::OpaqueType - | ObligationCauseCode::MiscObligation => {} + | ObligationCauseCode::MiscObligation + | ObligationCauseCode::WellFormed(..) => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 120680092ba..21ed586ab56 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -717,6 +717,10 @@ fn substs_infer_vars<'a, 'tcx>( fn to_fulfillment_error<'tcx>( error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, ) -> FulfillmentError<'tcx> { - let obligation = error.backtrace.into_iter().next().unwrap().obligation; - FulfillmentError::new(obligation, error.error) + let mut iter = error.backtrace.into_iter(); + let obligation = iter.next().unwrap().obligation; + // The root obligation is the last item in the backtrace - if there's only + // one item, then it's the same as the main obligation + let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); + FulfillmentError::new(obligation, error.error, root_obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 708688fa8a6..f17965f6f6b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -28,6 +28,7 @@ use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectionCacheKeyExt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -48,7 +49,6 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::iter; -use std::rc::Rc; pub use rustc_middle::traits::select::*; @@ -2168,7 +2168,7 @@ impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { // by using -Z verbose or just a CLI argument. let derived_cause = DerivedObligationCause { parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), + parent_code: Lrc::new(obligation.cause.code.clone()), }; let derived_code = variant(derived_cause); ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f592cf1cd24..9ee6eeb1fd5 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1,6 +1,7 @@ use crate::infer::InferCtxt; use crate::opaque_types::required_region_bounds; use crate::traits; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; @@ -9,7 +10,6 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstnes use rustc_span::Span; use std::iter; -use std::rc::Rc; /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved @@ -295,7 +295,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_ref() { let derived_cause = traits::DerivedObligationCause { parent_trait_ref: parent_trait_ref.value, - parent_code: Rc::new(obligation.cause.code.clone()), + parent_code: Lrc::new(obligation.cause.code.clone()), }; cause.make_mut().code = traits::ObligationCauseCode::DerivedObligation(derived_cause); diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 6304f696b00..2c55ea7f5c1 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -67,8 +67,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { { self.infcx .partially_normalize_associated_types_in( - DUMMY_SP, - hir::CRATE_HIR_ID, + ObligationCause::misc(DUMMY_SP, hir::CRATE_HIR_ID), self.param_env, value, ) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 9e89804b747..ba76b9c8dd5 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -640,7 +640,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error(&obligation, &err, false, false); + self.report_selection_error( + obligation.clone(), + &obligation, + &err, + false, + false, + ); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 33bc25accb3..3ea59906d3d 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::AllowTwoPhase; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -201,7 +202,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sole_field = &variant.fields[0]; let sole_field_ty = sole_field.ty(self.tcx, substs); if self.can_coerce(expr_ty, sole_field_ty) { - let variant_path = self.tcx.def_path_str(variant.def_id); + let variant_path = + with_no_trimmed_paths(|| self.tcx.def_path_str(variant.def_id)); // FIXME #56861: DRYer prelude filtering if let Some(path) = variant_path.strip_prefix("std::prelude::") { if let Some((_, path)) = path.split_once("::") { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 8e33f4f9e12..e045c30e0de 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -39,7 +39,7 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, + self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, }; use std::collections::hash_map::Entry; @@ -408,6 +408,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value } + /// Convenience method which tracks extra diagnostic information for normalization + /// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item + /// whose type is being wf-checked - this is used to construct a more precise span if + /// an error occurs. + /// + /// It is never necessary to call this method - calling `normalize_associated_types_in` will + /// just result in a slightly worse diagnostic span, and will still be sound. + pub(in super::super) fn normalize_associated_types_in_wf<T>( + &self, + span: Span, + value: T, + hir_id: hir::HirId, + ) -> T + where + T: TypeFoldable<'tcx>, + { + self.inh.normalize_associated_types_in_with_cause( + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(hir_id))), + self.param_env, + value, + ) + } + pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: T) -> T where T: TypeFoldable<'tcx>, @@ -423,7 +446,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) + self.inh.partially_normalize_associated_types_in( + ObligationCause::misc(span, self.body_id), + self.param_env, + value, + ) } pub fn require_type_meets( diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 2e9bef15f90..237861f1dd2 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt}; use rustc_span::{self, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::opaque_types::OpaqueTypeDecl; -use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; use std::cell::RefCell; use std::ops::Deref; @@ -162,7 +162,23 @@ impl Inherited<'a, 'tcx> { where T: TypeFoldable<'tcx>, { - let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); + self.normalize_associated_types_in_with_cause( + ObligationCause::misc(span, body_id), + param_env, + value, + ) + } + + pub(super) fn normalize_associated_types_in_with_cause<T>( + &self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + let ok = self.partially_normalize_associated_types_in(cause, param_env, value); self.register_infer_ok_obligations(ok) } } diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index ff7d291d3c9..34d0908bcc7 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -112,11 +112,9 @@ use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; +use rustc_middle::ty::{self, Ty, TyCtxt, UserType}; use rustc_session::config; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -321,117 +319,6 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDe &*tcx.typeck(def_id).used_trait_imports } -/// Inspects the substs of opaque types, replacing any inference variables -/// with proper generic parameter from the identity substs. -/// -/// This is run after we normalize the function signature, to fix any inference -/// variables introduced by the projection of associated types. This ensures that -/// any opaque types used in the signature continue to refer to generic parameters, -/// allowing them to be considered for defining uses in the function body -/// -/// For example, consider this code. -/// -/// ```rust -/// trait MyTrait { -/// type MyItem; -/// fn use_it(self) -> Self::MyItem -/// } -/// impl<T, I> MyTrait for T where T: Iterator<Item = I> { -/// type MyItem = impl Iterator<Item = I>; -/// fn use_it(self) -> Self::MyItem { -/// self -/// } -/// } -/// ``` -/// -/// When we normalize the signature of `use_it` from the impl block, -/// we will normalize `Self::MyItem` to the opaque type `impl Iterator<Item = I>` -/// However, this projection result may contain inference variables, due -/// to the way that projection works. We didn't have any inference variables -/// in the signature to begin with - leaving them in will cause us to incorrectly -/// conclude that we don't have a defining use of `MyItem`. By mapping inference -/// variables back to the actual generic parameters, we will correctly see that -/// we have a defining use of `MyItem` -fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: T) -> T -where - T: TypeFoldable<'tcx>, -{ - struct FixupFolder<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Opaque(def_id, substs) => { - debug!("fixup_opaque_types: found type {:?}", ty); - // Here, we replace any inference variables that occur within - // the substs of an opaque type. By definition, any type occurring - // in the substs has a corresponding generic parameter, which is what - // we replace it with. - // This replacement is only run on the function signature, so any - // inference variables that we come across must be the rust of projection - // (there's no other way for a user to get inference variables into - // a function signature). - if ty.needs_infer() { - let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { - let old_param = substs[param.index as usize]; - match old_param.unpack() { - GenericArgKind::Type(old_ty) => { - if let ty::Infer(_) = old_ty.kind() { - // Replace inference type with a generic parameter - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Const(old_const) => { - if let ty::ConstKind::Infer(_) = old_const.val { - // This should never happen - we currently do not support - // 'const projections', e.g.: - // `impl<T: SomeTrait> MyTrait for T where <T as SomeTrait>::MyConst == 25` - // which should be the only way for us to end up with a const inference - // variable after projection. If Rust ever gains support for this kind - // of projection, this should *probably* be changed to - // `self.tcx.mk_param_from_def(param)` - bug!( - "Found infer const: `{:?}` in opaque type: {:?}", - old_const, - ty - ); - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Lifetime(old_region) => { - if let RegionKind::ReVar(_) = old_region { - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - } - }); - let new_ty = self.tcx.mk_opaque(def_id, new_substs); - debug!("fixup_opaque_types: new type: {:?}", new_ty); - new_ty - } else { - ty - } - } - _ => ty.super_fold_with(self), - } - } - } - - debug!("fixup_opaque_types({:?})", val); - val.fold_with(&mut FixupFolder { tcx }) -} - fn typeck_const_arg<'tcx>( tcx: TyCtxt<'tcx>, (did, param_did): (LocalDefId, DefId), @@ -510,8 +397,6 @@ fn typeck_with_fallback<'tcx>( fn_sig, ); - let fn_sig = fixup_opaque_types(tcx, fn_sig); - let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; fcx } else { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 2879614d0c8..981a040e660 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -864,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &'tcx Pat<'tcx>, qpath: &'tcx hir::QPath<'tcx>, - subpats: &'tcx [&'tcx Pat<'tcx>], + subpats: &'tcx [Pat<'tcx>], ddpos: Option<usize>, expected: Ty<'tcx>, def_bm: BindingMode, @@ -982,7 +982,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_span: Span, res: Res, qpath: &hir::QPath<'_>, - subpats: &'tcx [&'tcx Pat<'tcx>], + subpats: &'tcx [Pat<'tcx>], fields: &'tcx [ty::FieldDef], expected: Ty<'tcx>, had_err: bool, @@ -1112,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_tuple( &self, span: Span, - elements: &'tcx [&'tcx Pat<'tcx>], + elements: &'tcx [Pat<'tcx>], ddpos: Option<usize>, expected: Ty<'tcx>, def_bm: BindingMode, @@ -1746,9 +1746,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_slice( &self, span: Span, - before: &'tcx [&'tcx Pat<'tcx>], + before: &'tcx [Pat<'tcx>], slice: Option<&'tcx Pat<'tcx>>, - after: &'tcx [&'tcx Pat<'tcx>], + after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 26d3cc9d891..bff391eb2d7 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -387,7 +387,7 @@ fn check_associated_item( ) { debug!("check_associated_item: {:?}", item_id); - let code = ObligationCauseCode::MiscObligation; + let code = ObligationCauseCode::WellFormed(Some(item_id)); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -401,7 +401,7 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, ty); + let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -423,7 +423,7 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in(span, ty); + let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -515,7 +515,8 @@ fn check_type_defn<'tcx, F>( fcx.register_wf_obligation( field.ty.into(), field.span, - ObligationCauseCode::MiscObligation, + // We don't have an HIR id for the field + ObligationCauseCode::WellFormed(None), ) } @@ -621,7 +622,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in(ty_span, ty); + let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, item_id); let mut forbid_unsized = true; if allow_foreign_ty { @@ -631,7 +632,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo } } - fcx.register_wf_obligation(item_ty.into(), ty_span, ObligationCauseCode::MiscObligation); + fcx.register_wf_obligation( + item_ty.into(), + ty_span, + ObligationCauseCode::WellFormed(Some(item_id)), + ); if forbid_unsized { fcx.register_bound( item_ty, @@ -680,7 +685,7 @@ fn check_impl<'tcx>( fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, - ObligationCauseCode::MiscObligation, + ObligationCauseCode::WellFormed(Some(item.hir_id())), ); } } @@ -746,7 +751,7 @@ fn check_where_clauses<'tcx, 'fcx>( fcx.register_wf_obligation( default_ct.into(), tcx.def_span(param.def_id), - ObligationCauseCode::MiscObligation, + ObligationCauseCode::WellFormed(None), ); } } @@ -900,7 +905,7 @@ fn check_fn_or_method<'fcx, 'tcx>( let sig = fcx.normalize_associated_types_in(span, sig); for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) { - fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::MiscObligation); + fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::WellFormed(None)); } implied_bounds.extend(sig.inputs()); diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 589570f1cb7..0aa059b7de8 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -496,6 +496,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { debug_assert!(!instantiated_ty.has_escaping_bound_vars()); + let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap(); + // Prevent: // * `fn foo<T>() -> Foo<T>` // * `fn foo<T: Bound + Other>() -> Foo<T>` @@ -508,6 +510,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // fn foo<U>() -> Foo<U> { .. } // ``` // figures out the concrete type with `U`, but the stored type is with `T`. + + // FIXME: why are we calling this here? This seems too early, and duplicated. let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( opaque_type_key, instantiated_ty, @@ -529,33 +533,33 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - if !opaque_type_key.substs.needs_infer() { - // We only want to add an entry into `concrete_opaque_types` - // if we actually found a defining usage of this opaque type. - // Otherwise, we do nothing - we'll either find a defining usage - // in some other location, or we'll end up emitting an error due - // to the lack of defining usage - if !skip_add { - let old_concrete_ty = self - .typeck_results - .concrete_opaque_types - .insert(opaque_type_key, definition_ty); - if let Some(old_concrete_ty) = old_concrete_ty { - if old_concrete_ty != definition_ty { - span_bug!( - span, - "`visit_opaque_types` tried to write different types for the same \ + if opaque_type_key.substs.needs_infer() { + span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs) + } + + // We only want to add an entry into `concrete_opaque_types` + // if we actually found a defining usage of this opaque type. + // Otherwise, we do nothing - we'll either find a defining usage + // in some other location, or we'll end up emitting an error due + // to the lack of defining usage + if !skip_add { + let old_concrete_ty = self + .typeck_results + .concrete_opaque_types + .insert(opaque_type_key, definition_ty); + if let Some(old_concrete_ty) = old_concrete_ty { + if old_concrete_ty != definition_ty { + span_bug!( + span, + "`visit_opaque_types` tried to write different types for the same \ opaque type: {:?}, {:?}, {:?}, {:?}", - opaque_type_key.def_id, - definition_ty, - opaque_defn, - old_concrete_ty, - ); - } + opaque_type_key.def_id, + definition_ty, + opaque_defn, + old_concrete_ty, + ); } } - } else { - self.tcx().sess.delay_span_bug(span, "`opaque_defn` has inference variables"); } } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index ee84974cb73..7b0002914ec 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -509,11 +509,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } +#[instrument(skip(tcx), level = "debug")] fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; - debug!("find_opaque_ty_constraints({:?})", def_id); - struct ConstraintLocator<'tcx> { tcx: TyCtxt<'tcx>, def_id: DefId, @@ -522,13 +521,11 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } impl ConstraintLocator<'_> { + #[instrument(skip(self), level = "debug")] fn check(&mut self, def_id: LocalDefId) { // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_results(def_id) { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no typeck results", - self.def_id, def_id, - ); + debug!("no constraint: no typeck results"); return; } // Calling `mir_borrowck` can lead to cycle errors through @@ -540,21 +537,19 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { .get_by(|(key, _)| key.def_id == self.def_id) .is_none() { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", - self.def_id, def_id, - ); + debug!("no constraints in typeck results"); return; } // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; - if let Some((opaque_type_key, concrete_type)) = - concrete_opaque_types.iter().find(|(key, _)| key.def_id == self.def_id) - { - debug!( - "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", - self.def_id, def_id, concrete_type, - ); + debug!(?concrete_opaque_types); + for (opaque_type_key, concrete_type) in concrete_opaque_types { + if opaque_type_key.def_id != self.def_id { + // Ignore constraints for other opaque types. + continue; + } + + debug!(?concrete_type, ?opaque_type_key.substs, "found constraint"); // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); @@ -603,7 +598,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { if let Some((prev_span, prev_ty)) = self.found { if *concrete_type != prev_ty { - debug!("find_opaque_ty_constraints: span={:?}", span); + debug!(?span); // Found different concrete types for the opaque type. let mut err = self.tcx.sess.struct_span_err( span, @@ -619,11 +614,6 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { } else { self.found = Some((span, concrete_type)); } - } else { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", - self.def_id, def_id, - ); } } } diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs new file mode 100644 index 00000000000..fa9c44bb891 --- /dev/null +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -0,0 +1,133 @@ +use crate::collect::ItemCtxt; +use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::HirId; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_trait_selection::traits; + +pub fn provide(providers: &mut Providers) { + *providers = Providers { diagnostic_hir_wf_check, ..*providers }; +} + +// Ideally, this would be in `rustc_trait_selection`, but we +// need access to `ItemCtxt` +fn diagnostic_hir_wf_check<'tcx>( + tcx: TyCtxt<'tcx>, + (predicate, hir_id): (ty::Predicate<'tcx>, HirId), +) -> Option<ObligationCause<'tcx>> { + let hir = tcx.hir(); + // HIR wfcheck should only ever happen as part of improving an existing error + tcx.sess.delay_span_bug(hir.span(hir_id), "Performed HIR wfcheck without an existing error!"); + + // Currently, we only handle WF checking for items (e.g. associated items). + // It would be nice to extend this to handle wf checks inside functions. + let def_id = match tcx.hir().opt_local_def_id(hir_id) { + Some(def_id) => def_id, + None => return None, + }; + + // FIXME - figure out how we want to handle wf-checking for + // things inside a function body. + let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + + // To perform HIR-based WF checking, we iterate over all HIR types + // that occur 'inside' the item we're checking. For example, + // given the type `Option<MyStruct<u8>>`, we will check + // `Option<MyStruct<u8>>`, `MyStruct<u8>`, and `u8`. + // For each type, we perform a well-formed check, and see if we get + // an erorr that matches our expected predicate. We keep save + // the `ObligationCause` corresponding to the *innermost* type, + // which is the most specific type that we can point to. + // In general, the different components of an `hir::Ty` may have + // completely differentr spans due to macro invocations. Pointing + // to the most accurate part of the type can be the difference + // between a useless span (e.g. the macro invocation site) + // and a useful span (e.g. a user-provided type passed in to the macro). + // + // This approach is quite inefficient - we redo a lot of work done + // by the normal WF checker. However, this code is run at most once + // per reported error - it will have no impact when compilation succeeds, + // and should only have an impact if a very large number of errors are + // displaydd to the user. + struct HirWfCheck<'tcx> { + tcx: TyCtxt<'tcx>, + predicate: ty::Predicate<'tcx>, + cause: Option<ObligationCause<'tcx>>, + cause_depth: usize, + icx: ItemCtxt<'tcx>, + hir_id: HirId, + param_env: ty::ParamEnv<'tcx>, + depth: usize, + } + + impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { + type Map = intravisit::ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + self.tcx.infer_ctxt().enter(|infcx| { + let mut fulfill = traits::FulfillmentContext::new(); + let tcx_ty = self.icx.to_ty(ty); + let cause = traits::ObligationCause::new( + ty.span, + self.hir_id, + traits::ObligationCauseCode::MiscObligation, + ); + fulfill.register_predicate_obligation( + &infcx, + traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx), + ), + ); + + if let Err(errors) = fulfill.select_all_or_error(&infcx) { + tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors); + for error in errors { + if error.obligation.predicate == self.predicate { + // Save the cause from the greatest depth - this corresponds + // to picking more-specific types (e.g. `MyStruct<u8>`) + // over less-specific types (e.g. `Option<MyStruct<u8>>`) + if self.depth >= self.cause_depth { + self.cause = Some(error.obligation.cause); + self.cause_depth = self.depth + } + } + } + } + }); + self.depth += 1; + intravisit::walk_ty(self, ty); + self.depth -= 1; + } + } + + let mut visitor = HirWfCheck { + tcx, + predicate, + cause: None, + cause_depth: 0, + icx, + hir_id, + param_env: tcx.param_env(def_id.to_def_id()), + depth: 0, + }; + + let ty = match tcx.hir().get(hir_id) { + hir::Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::TyAlias(ref ty) => Some(ty), + _ => None, + }, + _ => None, + }; + if let Some(ty) = ty { + visitor.visit_ty(ty); + } + visitor.cause +} diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 92ef8297472..5b717862e02 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -88,6 +88,7 @@ mod coherence; mod collect; mod constrained_generic_params; mod errors; +pub mod hir_wf_check; mod impl_wf_check; mod mem_categorization; mod outlives; @@ -462,6 +463,7 @@ pub fn provide(providers: &mut Providers) { variance::provide(providers); outlives::provide(providers); impl_wf_check::provide(providers); + hir_wf_check::provide(providers); } pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { |
