diff options
| author | bors <bors@rust-lang.org> | 2024-05-14 14:40:20 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-05-14 14:40:20 +0000 |
| commit | ac385a5af6d9fa8399a0cec799833cd28324abf8 (patch) | |
| tree | c66b9db6d2e2804081cac4f0928ae299ac13d790 /compiler | |
| parent | bdfd941f4dcbe54e0283433ac970febf4092fa6a (diff) | |
| parent | 31016d587936da143456bac5c9a89bcad8236bd3 (diff) | |
| download | rust-ac385a5af6d9fa8399a0cec799833cd28324abf8.tar.gz rust-ac385a5af6d9fa8399a0cec799833cd28324abf8.zip | |
Auto merge of #125120 - compiler-errors:rollup-mnjybwv, r=compiler-errors
Rollup of 7 pull requests Successful merges: - #119838 (style-guide: When breaking binops handle multi-line first operand better) - #124844 (Use a proper probe for shadowing impl) - #125047 (Migrate `run-make/issue-14500` to new `rmake.rs` format) - #125080 (only find segs chain for missing methods when no available candidates) - #125088 (Uplift `AliasTy` and `AliasTerm`) - #125100 (Don't do post-method-probe error reporting steps if we're in a suggestion) - #125118 (Use new utility functions/methods in run-make tests) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
26 files changed, 683 insertions, 571 deletions
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 2cc0167dbaa..d9add1c9b3b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -106,6 +106,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTrait } } +impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> { + 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 706f6f875bf..6da5adc7a6e 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<AssocItem> { - 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 f283c013805..5a9eab1ffea 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 11f288391c3..fe0dd4e393f 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 f82182fa058..a40fa600c19 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 81e179c9090..6cfdacf6a24 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 d50e9943384..db510d44392 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 2ddcb8aab25..9e944899026 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 e652f0586c4..5b3c50cb973 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 329d5f34a21..9dc30447f0e 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<TyCtxt<'tcx>>; +pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; +pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); @@ -184,6 +184,14 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> 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 7e49b0ac915..d7ae050ed4d 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 e831db1a41b..d7e185dd5e1 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<LocalDefId>; 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<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>; type BoundVars = &'tcx List<ty::BoundVariableKind>; type BoundVar = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; - 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<PolyExistentialPredicate<'tcx>>; 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>]) -> 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>, 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<Item = Self::GenericArg>) -> 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 dc5e881843a..93ccc0a7de4 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 e78856517b2..16ca098853e 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<TyCtxt<'tcx>>; +pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>; pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>; pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>; pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8d8ed70a757..3577db7234d 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 6abd685343b..7523cd15320 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<TyCtxt<'tcx>> for AliasTy<'tcx> { - fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( - 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<TyCtxt<'tcx>> for Pattern<'tcx> { fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( this: WithInfcx<'_, Infcx, &Self>, @@ -230,23 +213,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> 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<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { - fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( - 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 16301633247..74b03d6db66 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<TyCtxt<'tcx>>; -pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>; +pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>; +pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>; +pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>; 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 `<Ty as Trait<...>>::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<TyCtxt<'tcx>> for AliasTerm<'tcx> { - fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( - 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<TyCtxt<'tcx>> for AliasTerm<'tcx> { - fn new( - interner: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>, - ) -> 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<Item: Into<GenericArg<'tcx>>>, - ) -> 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 `<T as Iterator>::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 `<T as StreamingIterator>::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<AliasTy<'tcx>> 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<ty::UnevaluatedConst<'tcx>> 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 `<Ty as Trait<...>>::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<Item: Into<GenericArg<'tcx>>>, - ) -> 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 `<T as StreamingIterator>::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 `<T as Iterator>::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<TyCtxt<'tcx>> 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 9a027d7f937..97bea28f06a 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<Candidate<'tcx>>, ) { - // 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 6fda5f4af25..68c0c8bf09e 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 fd36b7ffd4e..b71a1b339cb 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 c748cdf6ed2..af07e9ff96b 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<I: Interner> DebugWithInfcx<I> for ConstKind<I> { } } +/// 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<I: Interner> { + pub def: I::DefId, + pub args: I::GenericArgs, +} + +impl<I: Interner> UnevaluatedConst<I> { + #[inline] + pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> { + UnevaluatedConst { def, args } + } +} + +impl<I: Interner> fmt::Debug for UnevaluatedConst<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> { + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + 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 5e981636438..92b1e08ab0a 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<I: Interner<Ty = Self>>: @@ -14,12 +15,15 @@ pub trait Ty<I: Interner<Ty = Self>>: + Hash + Eq + Into<I::GenericArg> + + Into<I::Term> + IntoKind<Kind = TyKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_alias(interner: I, kind: AliasTyKind, alias_ty: AliasTy<I>) -> Self; } pub trait Region<I: Interner<Region = Self>>: @@ -36,6 +40,7 @@ pub trait Const<I: Interner<Const = Self>>: + Hash + Eq + Into<I::GenericArg> + + Into<I::Term> + IntoKind<Kind = ConstKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> @@ -43,6 +48,8 @@ pub trait Const<I: Interner<Const = Self>>: { fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + fn new_unevaluated(interner: I, uv: UnevaluatedConst<I>, ty: I::Ty) -> Self; + fn ty(self) -> I::Ty; } @@ -89,21 +96,3 @@ pub trait BoundVars<I: Interner> { fn has_no_bound_vars(&self) -> bool; } - -pub trait AliasTerm<I: Interner>: Copy + DebugWithInfcx<I> + Hash + Eq + Sized { - fn new( - interner: I, - trait_def_id: I::DefId, - args: impl IntoIterator<Item: Into<I::GenericArg>>, - ) -> 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 af0e833b9e9..d6680977168 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<AliasTy<Self>> + + IrPrint<AliasTerm<Self>> + IrPrint<TraitRef<Self>> + IrPrint<TraitPredicate<Self>> + IrPrint<ExistentialTraitRef<Self>> @@ -27,6 +30,7 @@ pub trait Interner: type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs<Self>; + type GenericArgsSlice: Copy + Debug + Hash + Eq; type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -39,7 +43,6 @@ pub trait Interner: // Kinds of tys type Ty: Ty<Self>; type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>; - type AliasTy: Copy + DebugWithInfcx<Self> + 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<Self>; 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<Self>; 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<Self>) -> AliasTyKind; + + fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind; + + fn trait_ref_and_own_args_for_alias( + self, + def_id: Self::DefId, + args: Self::GenericArgs, + ) -> (TraitRef<Self>, Self::GenericArgsSlice); + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; + fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> 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 5885139754a..2a766d0bc09 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<T> { @@ -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 71f198d2b8e..b6c7c2c348c 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<I: Interner> ExistentialProjection<I> { /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`, /// then this function would return an `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef<I> { - 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<I> { + 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<I> { + pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> { // 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<I: Interner> ExistentialProjection<I> { } } - pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate<I>) -> Self { + pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> 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 `<Ty as Trait<...>>::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<I: Interner> { + /// 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<I: Interner> std::fmt::Debug for AliasTerm<I> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> { + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + 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<I: Interner> AliasTerm<I> { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator<Item: Into<I::GenericArg>>, + ) -> AliasTerm<I> { + 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<I> { + 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<I: Interner> AliasTerm<I> { + 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 `<T as StreamingIterator>::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>, 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 `<T as Iterator>::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<I> { + self.trait_ref_and_own_args(interner).0 + } +} + +impl<I: Interner> From<AliasTy<I>> for AliasTerm<I> { + fn from(ty: AliasTy<I>) -> Self { + AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } + } +} + +impl<I: Interner> From<UnevaluatedConst<I>> for AliasTerm<I> { + fn from(ct: UnevaluatedConst<I>) -> 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<I: Interner> { - pub projection_term: I::AliasTerm, + pub projection_term: AliasTerm<I>, pub term: I::Term, } @@ -371,16 +557,16 @@ impl<I: Interner> ProjectionPredicate<I> { self.projection_term.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate<I> { - 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<I> { + 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<I: Interner> fmt::Debug for ProjectionPredicate<I> { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct NormalizesTo<I: Interner> { - pub alias: I::AliasTerm, + pub alias: AliasTerm<I>, pub term: I::Term, } @@ -412,16 +598,16 @@ impl<I: Interner> NormalizesTo<I> { self.alias.self_ty() } - pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo<I> { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> { + 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 6e544d0e6ac..672c890f94e 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<I: Interner> { /// for `struct List<T>` 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<I: Interner> { /// 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<I>), /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`. Param(I::ParamTy), @@ -422,6 +422,154 @@ impl<I: Interner> fmt::Debug for TyKind<I> { } } +/// Represents the projection of an associated, opaque, or lazy-type-alias type. +/// +/// * For a projection, this would be `<Ty as Trait<...>>::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<I: Interner> { + /// 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<I: Interner> AliasTy<I> { + pub fn new( + interner: I, + def_id: I::DefId, + args: impl IntoIterator<Item: Into<I::GenericArg>>, + ) -> AliasTy<I> { + 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<I: Interner> AliasTy<I> { + 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 `<T as StreamingIterator>::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>, 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 `<T as Iterator>::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<I> { + self.trait_ref_and_own_args(interner).0 + } +} + +/// The following methods work only with inherent associated type projections. +impl<I: Interner> AliasTy<I> { + /// 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<I: Interner> fmt::Debug for AliasTy<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + WithInfcx::with_no_infcx(self).fmt(f) + } +} +impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> { + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + 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 { |
