diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 2cc0167dbaa6e..d9add1c9b3b52 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -106,6 +106,12 @@ impl IntoDiagArg for rustc_type_ir::ExistentialTrait } } +impl IntoDiagArg for rustc_type_ir::UnevaluatedConst { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + format!("{self:?}").into_diag_arg() + } +} + into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagArg for bool { diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 706f6f875bf64..6da5adc7a6e9b 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -938,14 +938,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - pub fn get_conversion_methods( + pub fn get_conversion_methods_for_diagnostic( &self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>, hir_id: hir::HirId, ) -> Vec { - let methods = self.probe_for_return_type( + let methods = self.probe_for_return_type_for_diagnostic( span, probe::Mode::MethodCall, expected, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f283c0138052e..5a9eab1ffeaf1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2414,7 +2414,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = if field.name == kw::Empty { self.dcx().span_delayed_bug(field.span, "field name with no name") - } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { + } else if self.method_exists_for_diagnostic( + field, + base_ty, + expr.hir_id, + expected.only_has_type(self), + ) { self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { self.ban_nonexisting_field(field, base, expr, base_ty) @@ -2600,7 +2605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = self.private_field_err(field, base_did); // Also check if an accessible method exists, which is often what is meant. - if self.method_exists(field, expr_t, expr.hir_id, return_ty) + if self.method_exists_for_diagnostic(field, expr_t, expr.hir_id, return_ty) && !self.expr_in_place(expr.hir_id) { self.suggest_method_call( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 11f288391c3bd..fe0dd4e393fc8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -290,7 +290,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + let methods = + self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id); if let Some((suggestion, msg, applicability, verbose, annotation)) = self.suggest_deref_or_ref(expr, found, expected) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index f82182fa0583c..a40fa600c19e2 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -91,7 +91,7 @@ pub enum CandidateSource { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a visible method named `method_name` or not. #[instrument(level = "debug", skip(self))] - pub fn method_exists( + pub fn method_exists_for_diagnostic( &self, method_name: Ident, self_ty: Ty<'tcx>, @@ -102,7 +102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe::Mode::MethodCall, method_name, return_type, - IsSuggestion(false), + IsSuggestion(true), self_ty, call_expr_id, ProbeScope::TraitsInScope, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 81e179c90900c..6cfdacf6a24d2 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -90,6 +90,11 @@ pub(crate) struct ProbeContext<'a, 'tcx> { >, scope_expr_id: HirId, + + /// Is this probe being done for a diagnostic? This will skip some error reporting + /// machinery, since we don't particularly care about, for example, similarly named + /// candidates if we're *reporting* similarly named candidates. + is_suggestion: IsSuggestion, } impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { @@ -220,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would use to decide if a method is a plausible fit for /// ambiguity purposes). #[instrument(level = "debug", skip(self, candidate_filter))] - pub fn probe_for_return_type( + pub fn probe_for_return_type_for_diagnostic( &self, span: Span, mode: Mode, @@ -459,6 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &orig_values, steps.steps, scope_expr_id, + is_suggestion, ); probe_cx.assemble_inherent_candidates(); @@ -553,6 +559,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { orig_steps_var_values: &'a OriginalQueryValues<'tcx>, steps: &'tcx [CandidateStep<'tcx>], scope_expr_id: HirId, + is_suggestion: IsSuggestion, ) -> ProbeContext<'a, 'tcx> { ProbeContext { fcx, @@ -570,6 +577,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { static_candidates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()), scope_expr_id, + is_suggestion, } } @@ -944,6 +952,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return r; } + // If it's a `lookup_probe_for_diagnostic`, then quit early. No need to + // probe for other candidates. + if self.is_suggestion.0 { + return Err(MethodError::NoMatch(NoMatchData { + static_candidates: vec![], + unsatisfied_predicates: vec![], + out_of_scope_traits: vec![], + similar_candidate: None, + mode: self.mode, + })); + } + debug!("pick: actual search failed, assemble diagnostics"); let static_candidates = std::mem::take(self.static_candidates.get_mut()); @@ -1631,6 +1651,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.orig_steps_var_values, self.steps, self.scope_expr_id, + IsSuggestion(true), ); pcx.allow_similar_names = true; pcx.assemble_inherent_candidates(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d50e99433842a..db510d44392cb 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1143,7 +1143,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let label_span_not_found = |err: &mut Diag<'_>| { + let mut find_candidate_for_method = false; + + let mut label_span_not_found = |err: &mut Diag<'_>| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match rcvr_ty.kind() { @@ -1219,6 +1221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(format!( "the {item_kind} was found for\n{type_candidates}{additional_types}" )); + find_candidate_for_method = mode == Mode::MethodCall; } } } else { @@ -1371,9 +1374,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - // If an appropriate error source is not found, check method chain for possible candiates - if unsatisfied_predicates.is_empty() - && let Mode::MethodCall = mode + + if !find_candidate_for_method { + self.lookup_segments_chain_for_no_match_method( + &mut err, + item_name, + item_kind, + source, + no_match_data, + ); + } + + self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); + Some(err) + } + + /// If an appropriate error source is not found, check method chain for possible candidates + fn lookup_segments_chain_for_no_match_method( + &self, + err: &mut Diag<'_>, + item_name: Ident, + item_kind: &str, + source: SelfSource<'tcx>, + no_match_data: &NoMatchData<'tcx>, + ) { + if no_match_data.unsatisfied_predicates.is_empty() + && let Mode::MethodCall = no_match_data.mode && let SelfSource::MethodCall(mut source_expr) = source { let mut stack_methods = vec![]; @@ -1394,6 +1420,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(Ty::new_misc_error(self.tcx)), ); + // FIXME: `probe_for_name_many` searches for methods in inherent implementations, + // so it may return a candidate that doesn't belong to this `revr_ty`. We need to + // check whether the instantiated type matches the received one. for _matched_method in self.probe_for_name_many( Mode::MethodCall, item_name, @@ -1416,8 +1445,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); - Some(err) } fn find_likely_intended_associated_item( @@ -2814,7 +2841,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; - let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type); + let method_exists = + self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); if method_exists { err.span_suggestion_verbose( diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index 2ddcb8aab2530..9e94489902674 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -153,6 +153,8 @@ pub enum ProbeKind<'tcx> { /// do a probe to find out what projection type(s) may be used to prove that /// the source type upholds all of the target type's object bounds. UpcastProjectionCompatibility, + /// Looking for param-env candidates that satisfy the trait ref for a projection. + ShadowedEnvProbing, /// Try to unify an opaque type with an existing key in the storage. OpaqueTypeStorageLookup { result: QueryResult<'tcx> }, } diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index e652f0586c4ea..5b3c50cb97323 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -118,6 +118,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeKind::TraitCandidate { source, result } => { write!(self.f, "CANDIDATE {source:?}: {result:?}") } + ProbeKind::ShadowedEnvProbing => { + write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:") + } }?; self.nested(|this| { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 329d5f34a2123..9dc30447f0e57 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -7,8 +7,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_type_ir::ConstKind as IrConstKind; -use rustc_type_ir::{TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; mod int; mod kind; @@ -20,7 +19,8 @@ use rustc_span::Span; use rustc_span::DUMMY_SP; pub use valtree::*; -pub type ConstKind<'tcx> = IrConstKind>; +pub type ConstKind<'tcx> = ir::ConstKind>; +pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); @@ -184,6 +184,14 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_bound(tcx, debruijn, var, ty) } + fn new_unevaluated( + interner: TyCtxt<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Self { + Const::new_unevaluated(interner, uv, ty) + } + fn ty(self) -> Ty<'tcx> { self.ty() } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 7e49b0ac915c6..d7ae050ed4d02 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,30 +1,15 @@ use super::Const; use crate::mir; use crate::ty::abstract_const::CastKind; -use crate::ty::GenericArgsRef; use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -/// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct UnevaluatedConst<'tcx> { - pub def: DefId, - pub args: GenericArgsRef<'tcx>, -} - -impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - format!("{self:?}").into_diag_arg() - } -} - -impl<'tcx> UnevaluatedConst<'tcx> { +#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)] +impl<'tcx> ty::UnevaluatedConst<'tcx> { /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this /// hurts performance. #[inline] - pub(crate) fn prepare_for_eval( + fn prepare_for_eval( self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -55,13 +40,6 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -impl<'tcx> UnevaluatedConst<'tcx> { - #[inline] - pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> { - UnevaluatedConst { def, args } - } -} - #[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e831db1a41bf8..d7e185dd5e107 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -76,6 +76,7 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -91,67 +92,124 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type DefiningOpaqueTypes = &'tcx ty::List; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; - type Term = ty::Term<'tcx>; + type Term = ty::Term<'tcx>; type Binder>> = Binder<'tcx, T>; type BoundVars = &'tcx List; type BoundVar = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List>; - type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; - type ErrorGuaranteed = ErrorGuaranteed; + type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List>; type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; - type Pat = Pattern<'tcx>; + type Pat = Pattern<'tcx>; type Const = ty::Const<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; - type ExprConst = ty::Expr<'tcx>; + type ExprConst = ty::Expr<'tcx>; type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; type InferRegion = ty::RegionVid; - type PlaceholderRegion = ty::PlaceholderRegion; + type PlaceholderRegion = ty::PlaceholderRegion; type Predicate = Predicate<'tcx>; type TraitPredicate = ty::TraitPredicate<'tcx>; type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; - type AliasTerm = ty::AliasTerm<'tcx>; type NormalizesTo = ty::NormalizesTo<'tcx>; type SubtypePredicate = ty::SubtypePredicate<'tcx>; type CoercePredicate = ty::CoercePredicate<'tcx>; type ClosureKind = ty::ClosureKind; - type Clauses = ty::Clauses<'tcx>; + type Clauses = ty::Clauses<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } type GenericsOf = &'tcx ty::Generics; + fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics { self.generics_of(def_id) } + fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> { + self.type_of(def_id).instantiate(self, args) + } + + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::Inherent + } else { + ty::Projection + } + } + DefKind::OpaqueTy => ty::Opaque, + DefKind::TyAlias => ty::Weak, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind { + match self.def_kind(alias.def_id) { + DefKind::AssocTy => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentTy + } else { + ty::AliasTermKind::ProjectionTy + } + } + DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, + DefKind::TyAlias => ty::AliasTermKind::WeakTy, + DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, + DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, + kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), + } + } + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { + assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); + let trait_def_id = self.parent(def_id); + assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); + let trait_generics = self.generics_of(trait_def_id); + ( + ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)), + &args[trait_generics.count()..], + ) + } + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { self.mk_args(args) } + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs { + self.mk_args_from_iter(args) + } + fn check_and_mk_args( self, def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dc5e881843a54..93ccc0a7de420 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -96,9 +96,9 @@ pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ - Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, - ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, - PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, + AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, + ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo, + OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, @@ -110,11 +110,11 @@ pub use self::region::{ }; pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ - AliasTerm, AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, - CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, - CoroutineClosureArgs, CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, - InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, - UpvarArgs, VarianceDiagInfo, + AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, CoroutineClosureSignature, FnSig, GenSig, InlineConstArgs, + InlineConstArgsParts, ParamConst, ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index e78856517b217..16ca098853eea 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -13,6 +13,7 @@ use crate::ty::{ }; pub type TraitRef<'tcx> = ir::TraitRef>; +pub type AliasTerm<'tcx> = ir::AliasTerm>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate>; pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8d8ed70a7574d..3577db7234d90 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3038,6 +3038,33 @@ define_print! { p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) } + ty::AliasTy<'tcx> { + let alias_term: ty::AliasTerm<'tcx> = (*self).into(); + p!(print(alias_term)) + } + + ty::AliasTerm<'tcx> { + match self.kind(cx.tcx()) { + ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::OpaqueTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + // If we're printing verbosely, or don't want to invoke queries + // (`is_impl_trait_in_trait`), then fall back to printing the def path. + // This is likely what you want if you're debugging the compiler anyways. + if !(cx.should_print_verbose() || with_reduced_queries()) + && cx.tcx().is_impl_trait_in_trait(self.def_id) + { + return cx.pretty_print_opaque_impl_type(self.def_id, self.args); + } else { + p!(print_def_path(self.def_id, self.args)); + } + } + } + } + ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); p!(pretty_print_bound_constness(self.trait_ref)); @@ -3205,33 +3232,6 @@ define_print_and_forward_display! { } } - ty::AliasTy<'tcx> { - let alias_term: ty::AliasTerm<'tcx> = (*self).into(); - p!(print(alias_term)) - } - - ty::AliasTerm<'tcx> { - match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - // If we're printing verbosely, or don't want to invoke queries - // (`is_impl_trait_in_trait`), then fall back to printing the def path. - // This is likely what you want if you're debugging the compiler anyways. - if !(cx.should_print_verbose() || with_reduced_queries()) - && cx.tcx().is_impl_trait_in_trait(self.def_id) - { - return cx.pretty_print_opaque_impl_type(self.def_id, self.args); - } else { - p!(print_def_path(self.def_id, self.args)); - } - } - } - } - ty::Predicate<'tcx> { p!(print(self.kind())) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6abd685343b3a..7523cd1532070 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_hir::def::Namespace; @@ -164,23 +164,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> { } } -impl<'tcx> fmt::Debug for AliasTy<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTy<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("AliasTy") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - impl<'tcx> DebugWithInfcx> for Pattern<'tcx> { fn fmt>>( this: WithInfcx<'_, Infcx, &Self>, @@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx> for ty::consts::Expr<'tcx> { } } -impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for ty::UnevaluatedConst<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - f.debug_struct("UnevaluatedConst") - .field("def", &this.data.def) - .field("args", &this.wrap(this.data.args)) - .finish() - } -} - impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 163016332475e..74b03d6db66db 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -28,20 +28,17 @@ use std::iter; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; -use rustc_type_ir::BoundVar; -use rustc_type_ir::CollectAndApply; -use rustc_type_ir::DynKind; -use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; -use rustc_type_ir::TypeAndMut as IrTypeAndMut; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind}; use super::fold::FnMutDelegate; use super::GenericParamDefKind; // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here #[rustc_diagnostic_item = "TyKind"] -pub type TyKind<'tcx> = IrTyKind>; -pub type TypeAndMut<'tcx> = IrTypeAndMut>; +pub type TyKind<'tcx> = ir::TyKind>; +pub type TypeAndMut<'tcx> = ir::TypeAndMut>; +pub type AliasTy<'tcx> = ir::AliasTy>; pub trait Article { fn article(&self) -> &'static str; @@ -1105,371 +1102,6 @@ where } } -/// Represents the unprojected term of a projection goal. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTerm<'tcx> { - /// The parameters of the associated or opaque item. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasTerm` without using - /// [AliasTerm::new]. - _use_alias_term_new_instead: (), -} - -// FIXME: Remove these when we uplift `AliasTerm` -use crate::ty::{DebugWithInfcx, InferCtxtLike, WithInfcx}; -impl<'tcx> std::fmt::Debug for AliasTerm<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - WithInfcx::with_no_infcx(self).fmt(f) - } -} -impl<'tcx> DebugWithInfcx> for AliasTerm<'tcx> { - fn fmt>>( - this: WithInfcx<'_, Infcx, &Self>, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { - f.debug_struct("AliasTerm") - .field("args", &this.map(|data| data.args)) - .field("def_id", &this.data.def_id) - .finish() - } -} - -impl<'tcx> rustc_type_ir::inherent::AliasTerm> for AliasTerm<'tcx> { - fn new( - interner: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator>>, - ) -> Self { - AliasTerm::new(interner, trait_def_id, args) - } - - fn def_id(self) -> DefId { - self.def_id - } - - fn args(self) -> ty::GenericArgsRef<'tcx> { - self.args - } - - fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId { - self.trait_def_id(interner) - } - - fn self_ty(self) -> Ty<'tcx> { - self.self_ty() - } - - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - self.with_self_ty(tcx, self_ty) - } -} - -impl<'tcx> AliasTerm<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> AliasTerm<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - AliasTerm { def_id, args, _use_alias_term_new_instead: () } - } - - pub fn expect_ty(self, tcx: TyCtxt<'tcx>) -> AliasTy<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::WeakTy => {} - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - bug!("Cannot turn `UnevaluatedConst` into `AliasTy`") - } - } - ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTermKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy => { - if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) { - ty::AliasTermKind::InherentTy - } else { - ty::AliasTermKind::ProjectionTy - } - } - DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, - DefKind::TyAlias => ty::AliasTermKind::WeakTy, - DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } -} - -/// The following methods work only with (trait) associated item projections. -impl<'tcx> AliasTerm<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTerm::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), - ) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// NOTE: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } - - /// Extracts the underlying trait reference and own args from this projection. - /// For example, if this is a projection of `::Item<'a>`, - /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args - pub fn trait_ref_and_own_args( - self, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - pub fn to_term(self, tcx: TyCtxt<'tcx>) -> ty::Term<'tcx> { - match self.kind(tcx) { - ty::AliasTermKind::ProjectionTy => Ty::new_alias( - tcx, - ty::Projection, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::InherentTy => Ty::new_alias( - tcx, - ty::Inherent, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::OpaqueTy => Ty::new_alias( - tcx, - ty::Opaque, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::WeakTy => Ty::new_alias( - tcx, - ty::Weak, - AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, - ) - .into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst::new(self.def_id, self.args), - tcx.type_of(self.def_id).instantiate(tcx, self.args), - ) - .into() - } - } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ty: AliasTy<'tcx>) -> Self { - AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } - } -} - -impl<'tcx> From> for AliasTerm<'tcx> { - fn from(ct: ty::UnevaluatedConst<'tcx>) -> Self { - AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } - } -} - -/// Represents the projection of an associated, opaque, or lazy-type-alias type. -/// -/// * For a projection, this would be `>::N<...>`. -/// * For an inherent projection, this would be `Ty::N<...>`. -/// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct AliasTy<'tcx> { - /// The parameters of the associated or opaque type. - /// - /// For a projection, these are the generic parameters for the trait and the - /// GAT parameters, if there are any. - /// - /// For an inherent projection, they consist of the self type and the GAT parameters, - /// if there are any. - /// - /// For RPIT the generic parameters are for the generics of the function, - /// while for TAIT it is used for the generic parameters of the alias. - pub args: GenericArgsRef<'tcx>, - - /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether - /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if - /// this is an opaque. - /// - /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the - /// underlying type if the type is an opaque. - /// - /// Note that if this is an associated type, this is not the `DefId` of the - /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`, - /// aka. `tcx.parent(def_id)`. - pub def_id: DefId, - - /// This field exists to prevent the creation of `AliasT` without using - /// [AliasTy::new]. - _use_alias_ty_new_instead: (), -} - -impl<'tcx> AliasTy<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - def_id: DefId, - args: impl IntoIterator>>, - ) -> ty::AliasTy<'tcx> { - let args = tcx.check_and_mk_args(def_id, args); - ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () } - } - - pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasTyKind { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy - if let DefKind::Impl { of_trait: false } = - tcx.def_kind(tcx.parent(self.def_id)) => - { - ty::Inherent - } - DefKind::AssocTy => ty::Projection, - DefKind::OpaqueTy => ty::Opaque, - DefKind::TyAlias => ty::Weak, - kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), - } - } - - /// Whether this alias type is an opaque. - pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool { - matches!(self.kind(tcx), ty::Opaque) - } - - pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - Ty::new_alias(tcx, self.kind(tcx), self) - } -} - -/// The following methods work only with (trait) associated type projections. -impl<'tcx> AliasTy<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.args.type_at(0) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1))) - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - match tcx.def_kind(self.def_id) { - DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id), - kind => bug!("expected a projection AliasTy; found {kind:?}"), - } - } - - /// Extracts the underlying trait reference and own args from this projection. - /// For example, if this is a projection of `::Item<'a>`, - /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args - pub fn trait_ref_and_own_args( - self, - tcx: TyCtxt<'tcx>, - ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { - let trait_def_id = self.trait_def_id(tcx); - let trait_generics = tcx.generics_of(trait_def_id); - ( - ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)), - &self.args[trait_generics.count()..], - ) - } - - /// Extracts the underlying trait reference from this projection. - /// For example, if this is a projection of `::Item`, - /// then this function would return a `T: Iterator` trait reference. - /// - /// WARNING: This will drop the args for generic associated types - /// consider calling [Self::trait_ref_and_own_args] to get those - /// as well. - pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - let def_id = self.trait_def_id(tcx); - ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id))) - } -} - -/// The following methods work only with inherent associated type projections. -impl<'tcx> AliasTy<'tcx> { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: ty::GenericArgsRef<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ty::GenericArgsRef<'tcx> { - debug_assert_eq!(self.kind(tcx), ty::Inherent); - - tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, @@ -2020,6 +1652,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } + + fn new_alias( + interner: TyCtxt<'tcx>, + kind: ty::AliasTyKind, + alias_ty: ty::AliasTy<'tcx>, + ) -> Self { + Ty::new_alias(interner, kind, alias_ty) + } } /// Type utilities diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9a027d7f937ec..97bea28f06a3a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,7 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. use crate::solve::GoalSource; -use crate::solve::{inspect, EvalCtxt, SolverMode}; +use crate::solve::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_middle::bug; @@ -16,7 +16,6 @@ use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use std::fmt::Debug; -use std::mem; pub(super) mod structural_traits; @@ -792,17 +791,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - // HACK: We temporarily remove the `ProofTreeBuilder` to - // avoid adding `Trait` candidates to the candidates used - // to prove the current goal. - let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop()); - 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); + + let mut trait_candidates_from_env = vec![]; + self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { + ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); + ecx.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 { @@ -831,7 +829,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } - self.inspect = inspect; } /// If there are multiple ways to prove a trait or projection goal, we have 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 6fda5f4af25e7..68c0c8bf09eac 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -176,7 +176,8 @@ fn to_selection<'tcx>( | ProbeKind::UnsizeAssembly | ProbeKind::UpcastProjectionCompatibility | ProbeKind::OpaqueTypeStorageLookup { result: _ } - | ProbeKind::Root { result: _ } => { + | ProbeKind::Root { result: _ } + | ProbeKind::ShadowedEnvProbing => { span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind()) } }) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index fd36b7ffd4eb4..b71a1b339cb81 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -18,8 +18,8 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal}; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty; use rustc_middle::ty::TypeFoldable; +use rustc_middle::{bug, ty}; use rustc_span::{Span, DUMMY_SP}; use crate::solve::eval_ctxt::canonical; @@ -290,12 +290,25 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { match *step { inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), inspect::ProbeStep::NestedProbe(ref probe) => { - // Nested probes have to prove goals added in their parent - // but do not leak them, so we truncate the added goals - // afterwards. - let num_goals = nested_goals.len(); - self.candidates_recur(candidates, nested_goals, probe); - nested_goals.truncate(num_goals); + match probe.kind { + // These never assemble candidates for the goal we're trying to solve. + inspect::ProbeKind::UpcastProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => continue, + + inspect::ProbeKind::NormalizedSelfTyAssembly + | inspect::ProbeKind::UnsizeAssembly + | inspect::ProbeKind::Root { .. } + | inspect::ProbeKind::TryNormalizeNonRigid { .. } + | inspect::ProbeKind::TraitCandidate { .. } + | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => { + // Nested probes have to prove goals added in their parent + // but do not leak them, so we truncate the added goals + // afterwards. + let num_goals = nested_goals.len(); + self.candidates_recur(candidates, nested_goals, probe); + nested_goals.truncate(num_goals); + } + } } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { assert_eq!(shallow_certainty.replace(c), None); @@ -308,9 +321,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { } match probe.kind { - inspect::ProbeKind::NormalizedSelfTyAssembly - | inspect::ProbeKind::UnsizeAssembly - | inspect::ProbeKind::UpcastProjectionCompatibility => (), + inspect::ProbeKind::UpcastProjectionCompatibility + | inspect::ProbeKind::ShadowedEnvProbing => bug!(), + + inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {} // We add a candidate even for the root evaluation if there // is only one way to prove a given goal, e.g. for `WellFormed`. diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index c748cdf6ed278..af07e9ff96bf8 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -2,6 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx}; @@ -86,6 +87,46 @@ impl DebugWithInfcx for ConstKind { } } +/// An unevaluated (potentially generic) constant used in the type-system. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct UnevaluatedConst { + pub def: I::DefId, + pub args: I::GenericArgs, +} + +impl UnevaluatedConst { + #[inline] + pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst { + UnevaluatedConst { def, args } + } +} + +impl fmt::Debug for UnevaluatedConst { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for UnevaluatedConst { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("UnevaluatedConst") + .field("def", &this.data.def) + .field("args", &this.wrap(this.data.args)) + .finish() + } +} + rustc_index::newtype_index! { /// A **`const`** **v**ariable **ID**. #[encodable] diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 5e98163643893..92b1e08ab0a36 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -5,7 +5,8 @@ use std::ops::Deref; use crate::fold::TypeSuperFoldable; use crate::visit::{Flags, TypeSuperVisitable}; use crate::{ - BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex, + AliasTy, AliasTyKind, BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, + TyKind, UnevaluatedConst, UniverseIndex, }; pub trait Ty>: @@ -14,12 +15,15 @@ pub trait Ty>: + Hash + Eq + Into + + Into + IntoKind> + TypeSuperVisitable + TypeSuperFoldable + Flags { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy) -> Self; } pub trait Region>: @@ -36,6 +40,7 @@ pub trait Const>: + Hash + Eq + Into + + Into + IntoKind> + TypeSuperVisitable + TypeSuperFoldable @@ -43,6 +48,8 @@ pub trait Const>: { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: UnevaluatedConst, ty: I::Ty) -> Self; + fn ty(self) -> I::Ty; } @@ -89,21 +96,3 @@ pub trait BoundVars { fn has_no_bound_vars(&self) -> bool; } - -pub trait AliasTerm: Copy + DebugWithInfcx + Hash + Eq + Sized { - fn new( - interner: I, - trait_def_id: I::DefId, - args: impl IntoIterator>, - ) -> Self; - - fn def_id(self) -> I::DefId; - - fn args(self) -> I::GenericArgs; - - fn trait_def_id(self, interner: I) -> I::DefId; - - fn self_ty(self) -> I::Ty; - - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; -} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index af0e833b9e983..d6680977168ec 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,13 +6,16 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ - CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, - NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate, + DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, NormalizesTo, ProjectionPredicate, + SubtypePredicate, TraitPredicate, TraitRef, }; pub trait Interner: Sized + Copy + + IrPrint> + + IrPrint> + IrPrint> + IrPrint> + IrPrint> @@ -27,6 +30,7 @@ pub trait Interner: type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs; + type GenericArgsSlice: Copy + Debug + Hash + Eq; type GenericArg: Copy + DebugWithInfcx + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -39,7 +43,6 @@ pub trait Interner: // Kinds of tys type Ty: Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; - type AliasTy: Copy + DebugWithInfcx + Hash + Eq + Sized; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq; type PlaceholderTy: PlaceholderLike; @@ -74,7 +77,6 @@ pub trait Interner: type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; type ProjectionPredicate: Copy + Debug + Hash + Eq; - type AliasTerm: AliasTerm; type NormalizesTo: Copy + Debug + Hash + Eq; type SubtypePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq; @@ -86,8 +88,23 @@ pub trait Interner: type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + // FIXME: Remove after uplifting `EarlyBinder` + fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty; + + fn alias_ty_kind(self, alias: AliasTy) -> AliasTyKind; + + fn alias_term_kind(self, alias: AliasTerm) -> AliasTermKind; + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (TraitRef, Self::GenericArgsSlice); + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; + fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; + fn check_and_mk_args( self, def_id: Self::DefId, diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 5885139754afe..2a766d0bc09c9 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -1,8 +1,8 @@ use std::fmt; use crate::{ - CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo, - ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, + AliasTerm, AliasTy, CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, + NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; pub trait IrPrint { @@ -43,6 +43,8 @@ define_display_via_print!( NormalizesTo, SubtypePredicate, CoercePredicate, + AliasTy, + AliasTerm, ); define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 71f198d2b8e84..b6c7c2c348cca 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -6,7 +6,9 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::visit::TypeVisitableExt as _; -use crate::{DebugWithInfcx, Interner}; +use crate::{ + AliasTy, AliasTyKind, DebugWithInfcx, InferCtxtLike, Interner, UnevaluatedConst, WithInfcx, +}; /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: @@ -272,20 +274,20 @@ impl ExistentialProjection { /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef { - let def_id = tcx.parent(self.def_id); - let args_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..args_count]); + pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef { + let def_id = interner.parent(self.def_id); + let args_count = interner.generics_of(def_id).count() - 1; + let args = interner.mk_args(&self.args[..args_count]); ExistentialTraitRef { def_id, args } } - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { + pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { // otherwise the escaping regions would be captured by the binders debug_assert!(!self_ty.has_escaping_bound_vars()); ProjectionPredicate { - projection_term: I::AliasTerm::new( - tcx, + projection_term: AliasTerm::new( + interner, self.def_id, [self_ty.into()].into_iter().chain(self.args), ), @@ -293,13 +295,13 @@ impl ExistentialProjection { } } - pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate) -> Self { + pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate) -> Self { // Assert there is a Self. - projection_predicate.projection_term.args().type_at(0); + projection_predicate.projection_term.args.type_at(0); Self { - def_id: projection_predicate.projection_term.def_id(), - args: tcx.mk_args(&projection_predicate.projection_term.args()[1..]), + def_id: projection_predicate.projection_term.def_id, + args: interner.mk_args(&projection_predicate.projection_term.args[1..]), term: projection_predicate.term, } } @@ -339,6 +341,190 @@ impl AliasTermKind { } } +/// Represents the unprojected term of a projection goal. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTerm { + /// The parameters of the associated or opaque item. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTerm` without using + /// [AliasTerm::new]. + _use_alias_term_new_instead: (), +} + +impl std::fmt::Debug for AliasTerm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTerm { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut std::fmt::Formatter<'_>, + ) -> std::fmt::Result { + f.debug_struct("AliasTerm") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + +impl AliasTerm { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTerm { + let args = interner.check_and_mk_args(def_id, args); + AliasTerm { def_id, args, _use_alias_term_new_instead: () } + } + + pub fn expect_ty(self, interner: I) -> AliasTy { + match self.kind(interner) { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::WeakTy => {} + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + } + } + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTermKind { + interner.alias_term_kind(self) + } + + pub fn to_term(self, interner: I) -> I::Term { + match self.kind(interner) { + AliasTermKind::ProjectionTy => Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into(), + AliasTermKind::InherentTy => Ty::new_alias( + interner, + AliasTyKind::Inherent, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into(), + AliasTermKind::OpaqueTy => Ty::new_alias( + interner, + AliasTyKind::Opaque, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into(), + AliasTermKind::WeakTy => Ty::new_alias( + interner, + AliasTyKind::Weak, + AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, + ) + .into(), + AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + I::Const::new_unevaluated( + interner, + UnevaluatedConst::new(self.def_id, self.args), + interner.type_of_instantiated(self.def_id, self.args), + ) + .into() + } + } + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTerm { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTerm::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert!( + matches!( + self.kind(interner), + AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst + ), + "expected a projection" + ); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: StreamingIterator` trait reference and + /// `['a]` as the own args. + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +impl From> for AliasTerm { + fn from(ty: AliasTy) -> Self { + AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } + } +} + +impl From> for AliasTerm { + fn from(ct: UnevaluatedConst) -> Self { + AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -362,7 +548,7 @@ impl AliasTermKind { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct ProjectionPredicate { - pub projection_term: I::AliasTerm, + pub projection_term: AliasTerm, pub term: I::Term, } @@ -371,16 +557,16 @@ impl ProjectionPredicate { self.projection_term.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { - Self { projection_term: self.projection_term.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.projection_term.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.projection_term.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.projection_term.def_id() + self.projection_term.def_id } } @@ -403,7 +589,7 @@ impl fmt::Debug for ProjectionPredicate { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct NormalizesTo { - pub alias: I::AliasTerm, + pub alias: AliasTerm, pub term: I::Term, } @@ -412,16 +598,16 @@ impl NormalizesTo { self.alias.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { + Self { alias: self.alias.with_self_ty(interner, self_ty), ..self } } - pub fn trait_def_id(self, tcx: I) -> I::DefId { - self.alias.trait_def_id(tcx) + pub fn trait_def_id(self, interner: I) -> I::DefId { + self.alias.trait_def_id(interner) } pub fn def_id(self) -> I::DefId { - self.alias.def_id() + self.alias.def_id } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6e544d0e6ace4..672c890f94edb 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -4,11 +4,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::Interner; -use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; +use crate::inherent::*; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, TraitRef, WithInfcx}; use self::TyKind::*; @@ -88,7 +88,7 @@ pub enum TyKind { /// for `struct List` and the args `[i32]`. /// /// Note that generic parameters in fields only get lazily instantiated - /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`. + /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`. Adt(I::AdtDef, I::GenericArgs), /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. @@ -201,7 +201,7 @@ pub enum TyKind { /// A projection, opaque type, weak type alias, or inherent associated type. /// All of these types are represented as pairs of def-id and args, and can /// be normalized, so they are grouped conceptually. - Alias(AliasTyKind, I::AliasTy), + Alias(AliasTyKind, AliasTy), /// A type parameter; for example, `T` in `fn f(x: T) {}`. Param(I::ParamTy), @@ -422,6 +422,154 @@ impl fmt::Debug for TyKind { } } +/// Represents the projection of an associated, opaque, or lazy-type-alias type. +/// +/// * For a projection, this would be `>::N<...>`. +/// * For an inherent projection, this would be `Ty::N<...>`. +/// * For an opaque type, there is no explicit syntax. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct AliasTy { + /// The parameters of the associated or opaque type. + /// + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. + /// + /// For an inherent projection, they consist of the self type and the GAT parameters, + /// if there are any. + /// + /// For RPIT the generic parameters are for the generics of the function, + /// while for TAIT it is used for the generic parameters of the alias. + pub args: I::GenericArgs, + + /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether + /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if + /// this is an opaque. + /// + /// During codegen, `interner.type_of(def_id)` can be used to get the type of the + /// underlying type if the type is an opaque. + /// + /// Note that if this is an associated type, this is not the `DefId` of the + /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`, + /// aka. `interner.parent(def_id)`. + pub def_id: I::DefId, + + /// This field exists to prevent the creation of `AliasTy` without using + /// [AliasTy::new]. + pub(crate) _use_alias_ty_new_instead: (), +} + +impl AliasTy { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> AliasTy { + let args = interner.check_and_mk_args(def_id, args); + AliasTy { def_id, args, _use_alias_ty_new_instead: () } + } + + pub fn kind(self, interner: I) -> AliasTyKind { + interner.alias_ty_kind(self) + } + + /// Whether this alias type is an opaque. + pub fn is_opaque(self, interner: I) -> bool { + matches!(self.kind(interner), AliasTyKind::Opaque) + } + + pub fn to_ty(self, interner: I) -> I::Ty { + Ty::new_alias(interner, self.kind(interner), self) + } +} + +/// The following methods work only with (trait) associated type projections. +impl AliasTy { + pub fn self_ty(self) -> I::Ty { + self.args.type_at(0) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + AliasTy::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + pub fn trait_def_id(self, interner: I) -> I::DefId { + assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection"); + interner.parent(self.def_id) + } + + /// Extracts the underlying trait reference and own args from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: StreamingIterator` trait reference and + /// `['a]` as the own args. + pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { + debug_assert_eq!(self.kind(interner), AliasTyKind::Projection); + interner.trait_ref_and_own_args_for_alias(self.def_id, self.args) + } + + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the args for generic associated types + /// consider calling [Self::trait_ref_and_own_args] to get those + /// as well. + pub fn trait_ref(self, interner: I) -> TraitRef { + self.trait_ref_and_own_args(interner).0 + } +} + +/// The following methods work only with inherent associated type projections. +impl AliasTy { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); + interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1))) + } +} + +impl fmt::Debug for AliasTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl DebugWithInfcx for AliasTy { + fn fmt>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + f.debug_struct("AliasTy") + .field("args", &this.map(|data| data.args)) + .field("def_id", &this.data.def_id) + .finish() + } +} + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum IntTy { diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md index 9d593f8081025..74e873e35ff38 100644 --- a/src/doc/style-guide/src/editions.md +++ b/src/doc/style-guide/src/editions.md @@ -40,6 +40,8 @@ include: of a delimited expression, delimited expressions are generally combinable, regardless of the number of members. Previously only applied with exactly one member (except for closures with explicit blocks). +- When line-breaking a binary operator, if the first operand spans multiple + lines, use the base indentation of the last line. - Miscellaneous `rustfmt` bugfixes. - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order). - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase". diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 171a24cd89d73..3bb0ee6d5ff6c 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -328,6 +328,37 @@ foo_bar Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather than at other binary operators. +If line-breaking at a binary operator (including assignment operators) where the +first operand spans multiple lines, use the base indentation of the *last* +line of the first operand, and indent relative to that: + +```rust +impl SomeType { + fn method(&mut self) { + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info = + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long; + + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info + + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long; + + self.array[array_index as usize] + .as_mut() + .expect("thing must exist") + .extra_info = Some(ExtraInfo { + parent, + count: count as u16, + children: children.into_boxed_slice(), + }); + } +} +``` + ### Casts (`as`) Format `as` casts like a binary operator. In particular, always include spaces diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 1671a01860ae4..7d239ff2e0a3a 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -150,6 +150,19 @@ impl Rustc { self } + /// Enables link time optimizations in rustc. Equivalent to `-Clto``. + pub fn lto(&mut self) -> &mut Self { + self.cmd.arg("-Clto"); + self + } + + /// Add a directory to the library search path. + pub fn library_search_path>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-L"); + self.cmd.arg(path.as_ref()); + self + } + /// Specify the edition year. pub fn edition(&mut self, edition: &str) -> &mut Self { self.cmd.arg("--edition"); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 83a3ea84b24d7..5f68f779c4eb0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -95,7 +95,6 @@ run-make/issue-107094/Makefile run-make/issue-10971-temps-dir/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-11908/Makefile -run-make/issue-14500/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile run-make/issue-18943/Makefile diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index ad0c2764df7aa..0613ef4839b14 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -26,8 +26,7 @@ fn main() { .arg("--test") .arg("--persist-doctests") .arg(out_dir) - .arg("--extern") - .arg(format!("t={}", extern_path.display())) + .extern_("t", extern_path) .run(); check_generated_binaries(); }); @@ -38,8 +37,7 @@ fn main() { .arg("--test") .arg("--persist-doctests") .arg(out_dir) - .arg("--extern") - .arg(format!("t={}", extern_path.display())) + .extern_("t", extern_path) .arg("--no-run") .run(); check_generated_binaries(); @@ -59,8 +57,7 @@ fn main() { .arg("doctests") .arg("--test-run-directory") .arg(run_dir) - .arg("--extern") - .arg("t=libt.rlib") + .extern_("t", "libt.rlib") .run(); remove_dir_all(run_dir_path); diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 6f89bf23b47c4..6cc7c6bbdafd2 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -29,8 +29,7 @@ fn main() { .arg(run_dir_name) .arg("--runtool") .arg(&run_tool_binary) - .arg("--extern") - .arg("t=libt.rlib") + .extern_("t", "libt.rlib") .current_dir(tmp_dir()) .run(); diff --git a/tests/run-make/issue-14500/Makefile b/tests/run-make/issue-14500/Makefile deleted file mode 100644 index eeab48de3b950..0000000000000 --- a/tests/run-make/issue-14500/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile - -# Test to make sure that reachable extern fns are always available in final -# productcs, including when LTO is used. In this test, the `foo` crate has a -# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate -# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the -# only way that `foo.c` will successfully compile. - -all: - $(RUSTC) foo.rs --crate-type=rlib - $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a - $(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo) - $(call RUN,foo) diff --git a/tests/run-make/issue-14500/bar.rs b/tests/run-make/reachable-extern-fn-available-lto/bar.rs similarity index 100% rename from tests/run-make/issue-14500/bar.rs rename to tests/run-make/reachable-extern-fn-available-lto/bar.rs diff --git a/tests/run-make/issue-14500/foo.c b/tests/run-make/reachable-extern-fn-available-lto/foo.c similarity index 100% rename from tests/run-make/issue-14500/foo.c rename to tests/run-make/reachable-extern-fn-available-lto/foo.c diff --git a/tests/run-make/issue-14500/foo.rs b/tests/run-make/reachable-extern-fn-available-lto/foo.rs similarity index 100% rename from tests/run-make/issue-14500/foo.rs rename to tests/run-make/reachable-extern-fn-available-lto/foo.rs diff --git a/tests/run-make/reachable-extern-fn-available-lto/rmake.rs b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs new file mode 100644 index 0000000000000..3e38b92b2b87d --- /dev/null +++ b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs @@ -0,0 +1,26 @@ +// Test to make sure that reachable extern fns are always available in final +// productcs, including when link time optimizations (LTO) are used. + +// In this test, the `foo` crate has a reahable symbol, +// and is a dependency of the `bar` crate. When the `bar` crate +// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the +// only way that `foo.c` will successfully compile. +// See https://github.com/rust-lang/rust/issues/14500 + +//@ ignore-cross-compile + +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib, tmp_dir}; + +fn main() { + let libbar_path = static_lib("bar"); + rustc().input("foo.rs").crate_type("rlib").run(); + rustc() + .input("bar.rs") + .crate_type("staticlib") + .lto() + .library_search_path(".") + .output(&libbar_path) + .run(); + cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run(); + run("foo"); +} diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs index aaa7fea0b6b78..d017b41bcdd29 100644 --- a/tests/run-make/rustdoc-map-file/rmake.rs +++ b/tests/run-make/rustdoc-map-file/rmake.rs @@ -1,5 +1,4 @@ -use run_make_support::{rustdoc, tmp_dir}; -use std::process::Command; +use run_make_support::{python_command, rustdoc, tmp_dir}; fn main() { let out_dir = tmp_dir().join("out"); @@ -10,6 +9,5 @@ fn main() { .output(&out_dir) .run(); // FIXME (GuillaumeGomez): Port the python script to Rust as well. - let python = std::env::var("PYTHON").unwrap_or("python".into()); - assert!(Command::new(python).arg("validate_json.py").arg(&out_dir).status().unwrap().success()); + assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success()); } diff --git a/tests/ui/const-generics/lookup-method.rs b/tests/ui/const-generics/lookup-method.rs new file mode 100644 index 0000000000000..915935c94a55a --- /dev/null +++ b/tests/ui/const-generics/lookup-method.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/124946 + +struct Builder; + +impl Builder { + fn cast(self) -> Builder { + Builder + } +} + +impl Builder { + fn build(self) {} +} + +fn main() { + let b = Builder::; + b.cast().build(); + //~^ ERROR: no method named `build` found for struct `Builder` in the current scope +} diff --git a/tests/ui/const-generics/lookup-method.stderr b/tests/ui/const-generics/lookup-method.stderr new file mode 100644 index 0000000000000..4cbd1e17c7bea --- /dev/null +++ b/tests/ui/const-generics/lookup-method.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `build` found for struct `Builder` in the current scope + --> $DIR/lookup-method.rs:17:14 + | +LL | struct Builder; + | -------------------------------------------- method `build` not found for this struct +... +LL | b.cast().build(); + | ^^^^^ method not found in `Builder` + | + = note: the method was found for + - `Builder` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs new file mode 100644 index 0000000000000..b6bc450dcc764 --- /dev/null +++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs @@ -0,0 +1,163 @@ +#![allow(non_snake_case)] + +// Ensures that we don't spend an unnecessary amount of compiler time building +// suggestions for mistyped methods. This used to happen because when we had method +// lookup failures, we would do subsequent method lookups, and those would themselves +// do extra work that was unnecessary for the purposes of suggestions. +// Fixed by #125100. + +macro_rules! traits { + ($($name:ident),*) => { + $( + trait $name { + fn $name(&self); + } + )* + } +} + +traits!( + A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, + A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, + A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, + A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, + A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, A90, A91, A92, A93, A94, A95, A96, + A97, A98, A99, A100, A101, A102, A103, A104, A105, A106, A107, A108, A109, A110, A111, A112, + A113, A114, A115, A116, A117, A118, A119, A120, A121, A122, A123, A124, A125, A126, A127, A128, + A129, A130, A131, A132, A133, A134, A135, A136, A137, A138, A139, A140, A141, A142, A143, A144, + A145, A146, A147, A148, A149, A150, A151, A152, A153, A154, A155, A156, A157, A158, A159, A160, + A161, A162, A163, A164, A165, A166, A167, A168, A169, A170, A171, A172, A173, A174, A175, A176, + A177, A178, A179, A180, A181, A182, A183, A184, A185, A186, A187, A188, A189, A190, A191, A192, + A193, A194, A195, A196, A197, A198, A199, A200, A201, A202, A203, A204, A205, A206, A207, A208, + A209, A210, A211, A212, A213, A214, A215, A216, A217, A218, A219, A220, A221, A222, A223, A224, + A225, A226, A227, A228, A229, A230, A231, A232, A233, A234, A235, A236, A237, A238, A239, A240, + A241, A242, A243, A244, A245, A246, A247, A248, A249, A250, A251, A252, A253, A254, A255, A256, + A257, A258, A259, A260, A261, A262, A263, A264, A265, A266, A267, A268, A269, A270, A271, A272, + A273, A274, A275, A276, A277, A278, A279, A280, A281, A282, A283, A284, A285, A286, A287, A288, + A289, A290, A291, A292, A293, A294, A295, A296, A297, A298, A299, A300, A301, A302, A303, A304, + A305, A306, A307, A308, A309, A310, A311, A312, A313, A314, A315, A316, A317, A318, A319, A320, + A321, A322, A323, A324, A325, A326, A327, A328, A329, A330, A331, A332, A333, A334, A335, A336, + A337, A338, A339, A340, A341, A342, A343, A344, A345, A346, A347, A348, A349, A350, A351, A352, + A353, A354, A355, A356, A357, A358, A359, A360, A361, A362, A363, A364, A365, A366, A367, A368, + A369, A370, A371, A372, A373, A374, A375, A376, A377, A378, A379, A380, A381, A382, A383, A384, + A385, A386, A387, A388, A389, A390, A391, A392, A393, A394, A395, A396, A397, A398, A399, A400, + A401, A402, A403, A404, A405, A406, A407, A408, A409, A410, A411, A412, A413, A414, A415, A416, + A417, A418, A419, A420, A421, A422, A423, A424, A425, A426, A427, A428, A429, A430, A431, A432, + A433, A434, A435, A436, A437, A438, A439, A440, A441, A442, A443, A444, A445, A446, A447, A448, + A449, A450, A451, A452, A453, A454, A455, A456, A457, A458, A459, A460, A461, A462, A463, A464, + A465, A466, A467, A468, A469, A470, A471, A472, A473, A474, A475, A476, A477, A478, A479, A480, + A481, A482, A483, A484, A485, A486, A487, A488, A489, A490, A491, A492, A493, A494, A495, A496, + A497, A498, A499, A500, A501, A502, A503, A504, A505, A506, A507, A508, A509, A510, A511, A512, + A513, A514, A515, A516, A517, A518, A519, A520, A521, A522, A523, A524, A525, A526, A527, A528, + A529, A530, A531, A532, A533, A534, A535, A536, A537, A538, A539, A540, A541, A542, A543, A544, + A545, A546, A547, A548, A549, A550, A551, A552, A553, A554, A555, A556, A557, A558, A559, A560, + A561, A562, A563, A564, A565, A566, A567, A568, A569, A570, A571, A572, A573, A574, A575, A576, + A577, A578, A579, A580, A581, A582, A583, A584, A585, A586, A587, A588, A589, A590, A591, A592, + A593, A594, A595, A596, A597, A598, A599, A600, A601, A602, A603, A604, A605, A606, A607, A608, + A609, A610, A611, A612, A613, A614, A615, A616, A617, A618, A619, A620, A621, A622, A623, A624, + A625, A626, A627, A628, A629, A630, A631, A632, A633, A634, A635, A636, A637, A638, A639, A640, + A641, A642, A643, A644, A645, A646, A647, A648, A649, A650, A651, A652, A653, A654, A655, A656, + A657, A658, A659, A660, A661, A662, A663, A664, A665, A666, A667, A668, A669, A670, A671, A672, + A673, A674, A675, A676, A677, A678, A679, A680, A681, A682, A683, A684, A685, A686, A687, A688, + A689, A690, A691, A692, A693, A694, A695, A696, A697, A698, A699, A700, A701, A702, A703, A704, + A705, A706, A707, A708, A709, A710, A711, A712, A713, A714, A715, A716, A717, A718, A719, A720, + A721, A722, A723, A724, A725, A726, A727, A728, A729, A730, A731, A732, A733, A734, A735, A736, + A737, A738, A739, A740, A741, A742, A743, A744, A745, A746, A747, A748, A749, A750, A751, A752, + A753, A754, A755, A756, A757, A758, A759, A760, A761, A762, A763, A764, A765, A766, A767, A768, + A769, A770, A771, A772, A773, A774, A775, A776, A777, A778, A779, A780, A781, A782, A783, A784, + A785, A786, A787, A788, A789, A790, A791, A792, A793, A794, A795, A796, A797, A798, A799, A800, + A801, A802, A803, A804, A805, A806, A807, A808, A809, A810, A811, A812, A813, A814, A815, A816, + A817, A818, A819, A820, A821, A822, A823, A824, A825, A826, A827, A828, A829, A830, A831, A832, + A833, A834, A835, A836, A837, A838, A839, A840, A841, A842, A843, A844, A845, A846, A847, A848, + A849, A850, A851, A852, A853, A854, A855, A856, A857, A858, A859, A860, A861, A862, A863, A864, + A865, A866, A867, A868, A869, A870, A871, A872, A873, A874, A875, A876, A877, A878, A879, A880, + A881, A882, A883, A884, A885, A886, A887, A888, A889, A890, A891, A892, A893, A894, A895, A896, + A897, A898, A899, A900, A901, A902, A903, A904, A905, A906, A907, A908, A909, A910, A911, A912, + A913, A914, A915, A916, A917, A918, A919, A920, A921, A922, A923, A924, A925, A926, A927, A928, + A929, A930, A931, A932, A933, A934, A935, A936, A937, A938, A939, A940, A941, A942, A943, A944, + A945, A946, A947, A948, A949, A950, A951, A952, A953, A954, A955, A956, A957, A958, A959, A960, + A961, A962, A963, A964, A965, A966, A967, A968, A969, A970, A971, A972, A973, A974, A975, A976, + A977, A978, A979, A980, A981, A982, A983, A984, A985, A986, A987, A988, A989, A990, A991, A992, + A993, A994, A995, A996, A997, A998, A999 +); + +#[derive(Default)] +struct M0 { + m1: M1, + m2: M1, + m3: M1, + m4: M1, + m5: M1, + m6: M1, + m7: M1, + m8: M1, + m9: M1, + m10: M1, + m11: M1, + m12: M1, + m13: M1, + m14: M1, + m15: M1, +} + +#[derive(Default)] +struct M1 { + m1: M2, + m2: M2, + m3: M2, + m4: M2, + m5: M2, + m6: M2, + m7: M2, + m8: M2, + m9: M2, + m10: M2, + m11: M2, + m12: M2, + m13: M2, + m14: M2, + m15: M2, +} + +#[derive(Default)] +struct M2 { + m1: M3, + m2: M3, + m3: M3, + m4: M3, + m5: M3, + m6: M3, + m7: M3, + m8: M3, + m9: M3, + m10: M3, + m11: M3, + m12: M3, + m13: M3, + m14: M3, + m15: M3, +} + +#[derive(Default)] +struct M3 {} + +fn main() { + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope + M0::default().Au(); + //~^ ERROR no method named `Au` found for struct `M0` in the current scope +} diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr new file mode 100644 index 0000000000000..f5c01ef8fe03b --- /dev/null +++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr @@ -0,0 +1,84 @@ +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:145:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:147:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:149:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:151:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:153:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:155:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:157:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:159:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error[E0599]: no method named `Au` found for struct `M0` in the current scope + --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:161:19 + | +LL | struct M0 { + | --------- method `Au` not found for this struct +... +LL | M0::default().Au(); + | ^^ method not found in `M0` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0599`.