From c74efbca71243fd3ccac0669d6a3d7297e49b69b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 May 2024 14:29:37 -0400 Subject: [PATCH 1/3] Make middle not rely on next_trait_solver --- Cargo.lock | 1 - compiler/rustc_middle/Cargo.toml | 1 - compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/traits/query.rs | 2 +- compiler/rustc_middle/src/traits/solve.rs | 4 ++-- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e950e2880727..99cb7196544e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4392,7 +4392,6 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_macros", - "rustc_next_trait_solver", "rustc_query_system", "rustc_serialize", "rustc_session", diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index ab0c598ea0c1b..d1cdabc293dd8 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -28,7 +28,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } -rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bf6ab80006455..de786c38326fa 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -62,7 +62,7 @@ macro_rules! arena_types { [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, [] canonical_goal_evaluation: - rustc_next_trait_solver::solve::inspect::CanonicalGoalEvaluationStep< + rustc_type_ir::solve::inspect::CanonicalGoalEvaluationStep< rustc_middle::ty::TyCtxt<'tcx> >, [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 63678ab659df9..202d587f0ad21 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,7 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_next_trait_solver::solve::BuiltinImplSource; +pub use rustc_type_ir::solve::BuiltinImplSource; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 66e50307733d6..3e9a2cb05fed2 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -13,7 +13,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; // FIXME: Remove this import and import via `traits::solve`. -pub use rustc_next_trait_solver::solve::NoSolution; +pub use rustc_type_ir::solve::NoSolution; pub mod type_op { use crate::ty::fold::TypeFoldable; diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c8c16ec1e2ce1..0d9ce402c64e5 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,8 +1,8 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; -use rustc_next_trait_solver as ir; -pub use rustc_next_trait_solver::solve::*; +use rustc_type_ir as ir; +pub use rustc_type_ir::solve::*; use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ From 82ef3ad98031377e20634d1f9f4aa3039db40025 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 May 2024 16:12:28 -0400 Subject: [PATCH 2/3] Uplift TypeError --- .../rustc_hir_analysis/src/check/check.rs | 1 + compiler/rustc_hir_typeck/src/expr.rs | 5 +- .../src/infer/error_reporting/mod.rs | 1 + .../infer/error_reporting/note_and_explain.rs | 7 +- .../infer/region_constraints/leak_check.rs | 2 +- compiler/rustc_middle/src/traits/query.rs | 7 - compiler/rustc_middle/src/ty/error.rs | 163 +++++------------- compiler/rustc_middle/src/ty/mod.rs | 32 ---- .../rustc_middle/src/ty/structural_impls.rs | 8 +- .../src/traits/error_reporting/suggestions.rs | 12 +- .../src/traits/select/mod.rs | 1 + compiler/rustc_type_ir/src/error.rs | 106 ++++++++++++ compiler/rustc_type_ir/src/lib.rs | 7 +- compiler/rustc_type_ir/src/macros.rs | 18 +- compiler/rustc_type_ir/src/predicate.rs | 33 ++++ compiler/rustc_type_ir/src/solve.rs | 6 +- 16 files changed, 216 insertions(+), 193 deletions(-) create mode 100644 compiler/rustc_type_ir/src/error.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 8a0623ef93e37..72e5995e892ec 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,6 +15,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7dd7b3ff055e5..f0f32ae07a95c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -40,7 +40,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; -use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -682,7 +682,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); - let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); + let error = + Some(TypeError::Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = self.err_ctxt().ty_kind_suggestion(self.param_env, ty) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fe0a246abbc6c..cee87f8f6e4d4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::Upcast; diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 19ef2d61fca31..b88677b3a4eca 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -21,13 +21,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { sp: Span, body_owner_def_id: DefId, ) { - use ty::error::TypeError::*; debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); let tcx = self.tcx; match err { - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { match (*values.expected.kind(), *values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { diag.note("no two closures, even if identical, have the same type"); @@ -483,7 +482,7 @@ impl Trait for X { values.found.kind(), ); } - CyclicTy(ty) => { + TypeError::CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( @@ -494,7 +493,7 @@ impl Trait for X { ); } } - TargetFeatureCast(def_id) => { + TypeError::TargetFeatureCast(def_id) => { let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 255ca52d3e98c..d05ac1d815185 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -276,7 +276,7 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); - TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound, other_region) } } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 3e9a2cb05fed2..50b6c77e1b29d 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -7,7 +7,6 @@ use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; -use crate::ty::error::TypeError; use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; @@ -91,12 +90,6 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize>>; -impl<'tcx> From> for NoSolution { - fn from(_: TypeError<'tcx>) -> NoSolution { - NoSolution - } -} - #[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec>, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 9e2c626478ac6..32dc9fa5fc621 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,89 +1,26 @@ use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter}; -use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; + use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; -use rustc_hir::def_id::DefId; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_span::symbol::Symbol; -use rustc_target::spec::abi; +use rustc_macros::extension; +pub use rustc_type_ir::error::ExpectedFound; + use std::borrow::Cow; use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::PathBuf; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] -pub struct ExpectedFound { - pub expected: T, - pub found: T, -} - -impl ExpectedFound { - pub fn new(a_is_expected: bool, a: T, b: T) -> Self { - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } - } -} - -// Data structures used in type unification -#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)] -#[rustc_pass_by_value] -pub enum TypeError<'tcx> { - Mismatch, - ConstnessMismatch(ExpectedFound), - PolarityMismatch(ExpectedFound), - SafetyMismatch(ExpectedFound), - AbiMismatch(ExpectedFound), - Mutability, - ArgumentMutability(usize), - TupleSize(ExpectedFound), - FixedArraySize(ExpectedFound), - ArgCount, - FieldMisMatch(Symbol, Symbol), - - RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsPlaceholderMismatch, - - Sorts(ExpectedFound>), - ArgumentSorts(ExpectedFound>, usize), - Traits(ExpectedFound), - VariadicMismatch(ExpectedFound), - - /// Instantiating a type variable with the given type would have - /// created a cycle (because it appears somewhere within that - /// type). - CyclicTy(Ty<'tcx>), - CyclicConst(ty::Const<'tcx>), - ProjectionMismatched(ExpectedFound), - ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), - ConstMismatch(ExpectedFound>), - - IntrinsicCast, - /// Safe `#[target_feature]` functions are not assignable to safe function pointers. - TargetFeatureCast(DefId), -} - -impl TypeError<'_> { - pub fn involves_regions(self) -> bool { - match self { - TypeError::RegionsDoesNotOutlive(_, _) - | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsPlaceholderMismatch => true, - _ => false, - } - } -} +pub type TypeError<'tcx> = rustc_type_ir::error::TypeError>; -/// Explains the source of a type err in a short, human readable way. This is meant to be placed -/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` -/// afterwards to present additional details, particularly when it comes to lifetime-related -/// errors. +/// Explains the source of a type err in a short, human readable way. +/// This is meant to be placed in parentheses after some larger message. +/// You should also invoke `note_and_explain_type_err()` afterwards +/// to present additional details, particularly when it comes to lifetime- +/// related errors. +#[extension(pub trait TypeErrorToStringExt<'tcx>)] impl<'tcx> TypeError<'tcx> { - pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { - use self::TypeError::*; + fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { fn report_maybe_different(expected: &str, found: &str) -> String { // A naive approach to making sure that we're not reporting silly errors such as: // (expected closure, found closure). @@ -95,24 +32,26 @@ impl<'tcx> TypeError<'tcx> { } match self { - CyclicTy(_) => "cyclic type of infinite size".into(), - CyclicConst(_) => "encountered a self-referencing constant".into(), - Mismatch => "types differ".into(), - ConstnessMismatch(values) => { + TypeError::CyclicTy(_) => "cyclic type of infinite size".into(), + TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(), + TypeError::Mismatch => "types differ".into(), + TypeError::ConstnessMismatch(values) => { format!("expected {} bound, found {} bound", values.expected, values.found).into() } - PolarityMismatch(values) => { + TypeError::PolarityMismatch(values) => { format!("expected {} polarity, found {} polarity", values.expected, values.found) .into() } - SafetyMismatch(values) => { + TypeError::SafetyMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - AbiMismatch(values) => { + TypeError::AbiMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - ArgumentMutability(_) | Mutability => "types differ in mutability".into(), - TupleSize(values) => format!( + TypeError::ArgumentMutability(_) | TypeError::Mutability => { + "types differ in mutability".into() + } + TypeError::TupleSize(values) => format!( "expected a tuple with {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -120,7 +59,7 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - FixedArraySize(values) => format!( + TypeError::FixedArraySize(values) => format!( "expected an array with a fixed size of {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -128,20 +67,21 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - ArgCount => "incorrect number of function parameters".into(), - FieldMisMatch(adt, field) => format!("field type mismatch: {adt}.{field}").into(), - RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), + TypeError::ArgCount => "incorrect number of function parameters".into(), + TypeError::RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), // Actually naming the region here is a bit confusing because context is lacking - RegionsInsufficientlyPolymorphic(..) => { + TypeError::RegionsInsufficientlyPolymorphic(..) => { + "one type is more general than the other".into() + } + TypeError::RegionsPlaceholderMismatch => { "one type is more general than the other".into() } - RegionsPlaceholderMismatch => "one type is more general than the other".into(), - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { let expected = values.expected.sort_string(tcx); let found = values.found.sort_string(tcx); report_maybe_different(&expected, &found).into() } - Traits(values) => { + TypeError::Traits(values) => { let (mut expected, mut found) = with_forced_trimmed_paths!(( tcx.def_path_str(values.expected), tcx.def_path_str(values.found), @@ -153,59 +93,34 @@ impl<'tcx> TypeError<'tcx> { report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`")) .into() } - VariadicMismatch(ref values) => format!( + TypeError::VariadicMismatch(ref values) => format!( "expected {} fn, found {} function", if values.expected { "variadic" } else { "non-variadic" }, if values.found { "variadic" } else { "non-variadic" } ) .into(), - ProjectionMismatched(ref values) => format!( + TypeError::ProjectionMismatched(ref values) => format!( "expected `{}`, found `{}`", tcx.def_path_str(values.expected), tcx.def_path_str(values.found) ) .into(), - ExistentialMismatch(ref values) => report_maybe_different( + TypeError::ExistentialMismatch(ref values) => report_maybe_different( &format!("trait `{}`", values.expected), &format!("trait `{}`", values.found), ) .into(), - ConstMismatch(ref values) => { + TypeError::ConstMismatch(ref values) => { format!("expected `{}`, found `{}`", values.expected, values.found).into() } - IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), - TargetFeatureCast(_) => { + TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), + TypeError::TargetFeatureCast(_) => { "cannot coerce functions with `#[target_feature]` to safe function pointers".into() } } } } -impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(self) -> bool { - use self::TypeError::*; - match self { - CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, - - Mutability - | ArgumentMutability(_) - | TupleSize(_) - | ArgCount - | FieldMisMatch(..) - | RegionsDoesNotOutlive(..) - | RegionsInsufficientlyPolymorphic(..) - | RegionsPlaceholderMismatch - | Traits(_) - | ProjectionMismatched(_) - | ExistentialMismatch(_) - | ConstMismatch(_) - | IntrinsicCast => true, - } - } -} - impl<'tcx> Ty<'tcx> { pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { match *self.kind() { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e0fbf127e7089..131c62d6d19ff 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -313,38 +313,6 @@ impl Visibility { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -pub enum BoundConstness { - /// `Type: Trait` - NotConst, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - /// - /// Requires resolving to const only when we are in a const context. - ConstIfConst, -} - -impl BoundConstness { - pub fn as_str(self) -> &'static str { - match self { - Self::NotConst => "", - Self::Const => "const", - Self::ConstIfConst => "~const", - } - } -} - -impl fmt::Display for BoundConstness { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::NotConst => f.write_str("normal"), - Self::Const => f.write_str("const"), - Self::ConstIfConst => f.write_str("~const"), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct ClosureSizeProfileData<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cf4854d13646a..cc6b1d57f8705 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -296,7 +296,6 @@ TrivialTypeTraversalImpls! { ::rustc_target::abi::FieldIdx, ::rustc_target::abi::VariantIdx, crate::middle::region::Scope, - crate::ty::FloatTy, ::rustc_ast::InlineAsmOptions, ::rustc_ast::InlineAsmTemplatePiece, ::rustc_ast::NodeId, @@ -316,7 +315,7 @@ TrivialTypeTraversalImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - crate::ty::BoundConstness, + crate::ty::BoundRegion, // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully @@ -324,16 +323,11 @@ TrivialTypeTraversalImpls! { crate::ty::BoundRegionKind, crate::ty::AssocItem, crate::ty::AssocKind, - crate::ty::AliasTyKind, crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::LateParamRegion, - crate::ty::InferTy, - crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, - crate::ty::RegionVid, - crate::ty::Variance, ::rustc_span::Span, ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6a96a03e047f7..c7da85bd1cc47 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -28,7 +28,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; -use rustc_middle::ty::error::TypeError::{self, Sorts}; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::PrintPolyTraitRefExt; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs, @@ -3842,7 +3842,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let Some(failed_pred) = failed_pred.as_projection_clause() && let Some(found) = failed_pred.skip_binder().term.as_type() { - type_diffs = vec![Sorts(ty::error::ExpectedFound { + type_diffs = vec![TypeError::Sorts(ty::error::ExpectedFound { expected: where_pred .skip_binder() .projection_term @@ -3985,7 +3985,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { continue; }; for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; if tcx.is_diagnostic_item(sym::IteratorItem, *def_id) @@ -4165,7 +4165,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if primary_spans.is_empty() || type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4198,7 +4198,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); if !self.can_eq(param_env, ty, *prev_ty) { if type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4248,7 +4248,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let ocx = ObligationCtxt::new(self.infcx); let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ce4fa5fa47cbc..9e6ae91251503 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -42,6 +42,7 @@ use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs new file mode 100644 index 0000000000000..27623ea9cacb0 --- /dev/null +++ b/compiler/rustc_type_ir/src/error.rs @@ -0,0 +1,106 @@ +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::solve::NoSolution; +use crate::{self as ty, Interner}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] +pub struct ExpectedFound { + pub expected: T, + pub found: T, +} + +impl ExpectedFound { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { + if a_is_expected { + ExpectedFound { expected: a, found: b } + } else { + ExpectedFound { expected: b, found: a } + } + } +} + +// Data structures used in type unification +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic)] +#[rustc_pass_by_value] +pub enum TypeError { + Mismatch, + ConstnessMismatch(ExpectedFound), + PolarityMismatch(ExpectedFound), + SafetyMismatch(ExpectedFound), + AbiMismatch(ExpectedFound), + Mutability, + ArgumentMutability(usize), + TupleSize(ExpectedFound), + FixedArraySize(ExpectedFound), + ArgCount, + + RegionsDoesNotOutlive(I::Region, I::Region), + RegionsInsufficientlyPolymorphic(I::BoundRegion, I::Region), + RegionsPlaceholderMismatch, + + Sorts(ExpectedFound), + ArgumentSorts(ExpectedFound, usize), + Traits(ExpectedFound), + VariadicMismatch(ExpectedFound), + + /// Instantiating a type variable with the given type would have + /// created a cycle (because it appears somewhere within that + /// type). + CyclicTy(I::Ty), + CyclicConst(I::Const), + ProjectionMismatched(ExpectedFound), + ExistentialMismatch(ExpectedFound), + ConstMismatch(ExpectedFound), + + IntrinsicCast, + /// Safe `#[target_feature]` functions are not assignable to safe function pointers. + TargetFeatureCast(I::DefId), +} + +impl TypeError { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } + + pub fn must_include_note(self) -> bool { + use self::TypeError::*; + match self { + CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) + | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) + | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, + + Mutability + | ArgumentMutability(_) + | TupleSize(_) + | ArgCount + | RegionsDoesNotOutlive(..) + | RegionsInsufficientlyPolymorphic(..) + | RegionsPlaceholderMismatch + | Traits(_) + | ProjectionMismatched(_) + | ExistentialMismatch(_) + | ConstMismatch(_) + | IntrinsicCast => true, + } + } +} + +impl From> for NoSolution { + fn from(_: TypeError) -> NoSolution { + NoSolution + } +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 217c056d0baee..7d363daa420ab 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -21,18 +21,19 @@ use std::hash::Hash; #[cfg(not(feature = "nightly"))] use std::sync::Arc as Lrc; +// These modules are `pub` since they are not glob-imported. #[macro_use] pub mod visit; #[cfg(feature = "nightly")] pub mod codec; +pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; pub mod lift; pub mod solve; -pub mod ty_info; -pub mod ty_kind; +// These modules are not `pub` since they are glob-imported. #[macro_use] mod macros; mod binder; @@ -46,6 +47,8 @@ mod interner; mod predicate; mod predicate_kind; mod region_kind; +mod ty_info; +mod ty_kind; mod upcast; pub use binder::*; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index f2f7b165de52f..aae5aeb5fb363 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -48,10 +48,22 @@ TrivialTypeTraversalImpls! { u32, u64, String, - crate::DebruijnIndex, crate::AliasRelationDirection, + crate::AliasTyKind, + crate::BoundConstness, + crate::DebruijnIndex, + crate::FloatTy, + crate::InferTy, + crate::IntVarValue, + crate::PredicatePolarity, + crate::RegionVid, + crate::solve::BuiltinImplSource, + crate::solve::Certainty, + crate::solve::GoalSource, + crate::solve::MaybeCause, + crate::solve::NoSolution, crate::UniverseIndex, - rustc_ast_ir::Mutability, + crate::Variance, rustc_ast_ir::Movability, - crate::PredicatePolarity, + rustc_ast_ir::Mutability, } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 9e0e52cfb4b7a..63a4c2e9d1f76 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -793,3 +793,36 @@ pub struct CoercePredicate { pub a: I::Ty, pub b: I::Ty, } + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +pub enum BoundConstness { + /// `Type: Trait` + NotConst, + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` + /// + /// Requires resolving to const only when we are in a const context. + ConstIfConst, +} + +impl BoundConstness { + pub fn as_str(self) -> &'static str { + match self { + Self::NotConst => "", + Self::Const => "const", + Self::ConstIfConst => "~const", + } + } +} + +impl fmt::Display for BoundConstness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NotConst => f.write_str("normal"), + Self::Const => f.write_str("const"), + Self::ConstIfConst => f.write_str("~const"), + } + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 3c24e851d7b63..45125fe619193 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -20,7 +20,6 @@ pub type CanonicalResponse = Canonical>; pub type QueryResult = Result, NoSolution>; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct NoSolution; @@ -60,7 +59,7 @@ impl Goal { /// /// This is necessary as we treat nested goals different depending on /// their source. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { Misc, @@ -170,7 +169,6 @@ pub enum CandidateSource { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] pub enum BuiltinImplSource { /// Some builtin impl we don't need to differentiate. This should be used @@ -214,7 +212,6 @@ pub struct Response { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty { Yes, @@ -252,7 +249,6 @@ impl Certainty { /// Why we failed to evaluate a goal. #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either From 91274c84b9f3790192219c71a8cb6908747beef4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 4 Jun 2024 16:02:36 -0400 Subject: [PATCH 3/3] Uplift TypeRelation and Relate --- Cargo.lock | 2 + .../rustc_borrowck/src/constraints/mod.rs | 4 +- .../rustc_borrowck/src/region_infer/mod.rs | 2 +- .../src/type_check/relate_tys.rs | 16 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_infer/Cargo.toml | 1 + compiler/rustc_infer/src/infer/at.rs | 4 +- .../src/infer/error_reporting/mod.rs | 12 +- compiler/rustc_infer/src/infer/mod.rs | 7 +- .../src/infer/outlives/test_type_match.rs | 17 +- .../infer/region_constraints/leak_check.rs | 2 +- .../src/infer/relate}/_match.rs | 22 +- .../rustc_infer/src/infer/relate/combine.rs | 17 +- .../src/infer/relate/generalize.rs | 15 +- compiler/rustc_infer/src/infer/relate/glb.rs | 10 +- .../src/infer/relate/higher_ranked.rs | 2 +- .../rustc_infer/src/infer/relate/lattice.rs | 2 +- compiler/rustc_infer/src/infer/relate/lub.rs | 10 +- compiler/rustc_infer/src/infer/relate/mod.rs | 20 +- .../src/infer/relate/type_relating.rs | 17 +- compiler/rustc_middle/src/ty/adt.rs | 6 + compiler/rustc_middle/src/ty/consts.rs | 8 + compiler/rustc_middle/src/ty/context.rs | 38 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/relate.rs | 817 +++--------------- compiler/rustc_middle/src/ty/sty.rs | 119 ++- compiler/rustc_next_trait_solver/Cargo.toml | 11 +- .../rustc_next_trait_solver/src/resolve.rs | 8 +- .../src/solve/eval_ctxt/mod.rs | 8 +- .../src/traits/select/mod.rs | 4 +- compiler/rustc_type_ir/src/inherent.rs | 56 +- compiler/rustc_type_ir/src/interner.rs | 46 +- compiler/rustc_type_ir/src/lib.rs | 1 + compiler/rustc_type_ir/src/relate.rs | 666 ++++++++++++++ 34 files changed, 1112 insertions(+), 864 deletions(-) rename compiler/{rustc_middle/src/ty => rustc_infer/src/infer/relate}/_match.rs (82%) create mode 100644 compiler/rustc_type_ir/src/relate.rs diff --git a/Cargo.lock b/Cargo.lock index 99cb7196544e8..019e7a3b16bd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4201,6 +4201,7 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4508,6 +4509,7 @@ dependencies = [ "rustc_serialize", "rustc_type_ir", "rustc_type_ir_macros", + "tracing", ] [[package]] diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index ff11e4db12133..97408fa20d79b 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,7 +1,7 @@ use rustc_data_structures::graph::scc::Sccs; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; use std::fmt; use std::ops::Index; @@ -97,7 +97,7 @@ pub struct OutlivesConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, /// Variance diagnostic information - pub variance_info: VarianceDiagInfo<'tcx>, + pub variance_info: VarianceDiagInfo>, /// If this constraint is promoted from closure requirements. pub from_closure: bool, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b57cf9066cf33..0e3140ca98b02 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2304,5 +2304,5 @@ pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, pub from_closure: bool, pub cause: ObligationCause<'tcx>, - pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub variance_info: ty::VarianceDiagInfo>, } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 9863c4a38832c..2c34fc583c835 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; +use rustc_infer::infer::relate::{ObligationEmittingRelation, StructurallyRelateAliases}; +use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -82,7 +82,7 @@ pub struct NllTypeRelating<'me, 'bccx, 'tcx> { /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, + ambient_variance_info: ty::VarianceDiagInfo>, } impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { @@ -296,7 +296,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { &mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo>, ) { let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); @@ -314,7 +314,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } } -impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -324,10 +324,10 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { } #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -445,7 +445,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { // We want that // diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 93726ce2b3eb1..dbaa6e398c886 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,6 +41,7 @@ use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause}; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -51,7 +52,6 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index c1565a7d40fd5..5136ab79a0f84 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 17e6d6250ad5e..046d908d148d0 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -27,8 +27,8 @@ use super::*; +use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; use rustc_middle::bug; -use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; /// Whether we should define opaque types or just treat them opaquely. @@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { +pub trait ToTrace<'tcx>: Relate> + Copy { fn to_trace( cause: &ObligationCause<'tcx>, a_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index cee87f8f6e4d4..ed483c6cbeb41 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,6 +58,7 @@ use crate::traits::{ PredicateObligation, }; +use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, @@ -73,7 +74,6 @@ use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; -use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::Upcast; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, @@ -2687,7 +2687,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. - pub fn same_type_modulo_infer>(&self, a: T, b: T) -> bool { + pub fn same_type_modulo_infer>>(&self, a: T, b: T) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() } @@ -2695,7 +2695,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); -impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { +impl<'tcx> TypeRelation> for SameTypeModuloInfer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.0.tcx } @@ -2704,10 +2704,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { "SameTypeModuloInfer" } - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, _variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo>, a: T, b: T, ) -> relate::RelateResult<'tcx, T> { @@ -2755,7 +2755,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: relate::Relate<'tcx>, + T: relate::Relate>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 4476611d9c820..c606ab808ef80 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,9 +1,6 @@ pub use at::DefineOpaqueTypes; pub use freshen::TypeFreshener; pub use lexical_region_resolve::RegionResolutionError; -pub use relate::combine::CombineFields; -pub use relate::combine::ObligationEmittingRelation; -pub use relate::StructurallyRelateAliases; pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; @@ -11,6 +8,7 @@ pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; pub use ValuePairs::*; +use crate::infer::relate::{CombineFields, RelateResult}; use crate::traits::{ self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; @@ -39,7 +37,6 @@ use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; @@ -62,7 +59,7 @@ pub mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; -mod relate; +pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 29c11d4247d02..978b92fd8980d 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -1,15 +1,12 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{ - self, - error::TypeError, - relate::{self, Relate, RelateResult, TypeRelation}, - Ty, TyCtxt, -}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use crate::infer::region_constraints::VerifyIfEq; +use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation}; /// Given a "verify-if-eq" type test like: /// @@ -135,7 +132,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { +impl<'tcx> TypeRelation> for MatchAgainstHigherRankedOutlives<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstHigherRankedOutlives" } @@ -145,10 +142,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { } #[instrument(level = "trace", skip(self))] - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -208,7 +205,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { value: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { self.pattern_depth.shift_in(1); let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?)); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index d05ac1d815185..5b159d6273121 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -1,11 +1,11 @@ use super::*; +use crate::infer::relate::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph}; use rustc_index::Idx; use rustc_middle::span_bug; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches new universes created during `snapshot`, looking for diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_infer/src/infer/relate/_match.rs similarity index 82% rename from compiler/rustc_middle/src/ty/_match.rs rename to compiler/rustc_infer/src/infer/relate/_match.rs index f30270abd5c1e..30a066a265acd 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_infer/src/infer/relate/_match.rs @@ -1,8 +1,10 @@ -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use tracing::{debug, instrument}; +use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; + /// A type "A" *matches* "B" if the fresh types in B could be /// instantiated with values so as to make it equal to A. Matching is /// intended to be used only on freshened types, and it basically @@ -29,7 +31,7 @@ impl<'tcx> MatchAgainstFreshVars<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { +impl<'tcx> TypeRelation> for MatchAgainstFreshVars<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstFreshVars" } @@ -38,10 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { self.tcx } - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, _: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -72,12 +74,12 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { ) => Ok(a), (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), - _ => relate::structurally_relate_tys(self, a, b), + _ => structurally_relate_tys(self, a, b), } } @@ -97,7 +99,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { } (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(a, b))); + return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))); } _ => {} @@ -112,7 +114,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index b193f4bcede66..30cb2bab90086 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -22,12 +22,13 @@ use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; use super::StructurallyRelateAliases; +use super::{RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::bug; use rustc_middle::infer::unify_key::EffectVarValue; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{RelateResult, TypeRelation}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::Span; @@ -121,7 +122,7 @@ impl<'tcx> InferCtxt<'tcx> { (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { match relation.structurally_relate_aliases() { StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_tys(relation, a, b) + relate::structurally_relate_tys(relation, a, b) } StructurallyRelateAliases::No => { relation.register_type_relate_obligation(a, b); @@ -132,7 +133,7 @@ impl<'tcx> InferCtxt<'tcx> { // All other cases of inference are errors (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } // During coherence, opaque types should be treated as *possibly* @@ -144,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::structurally_relate_tys(relation, a, b), + _ => relate::structurally_relate_tys(relation, a, b), } } @@ -234,11 +235,11 @@ impl<'tcx> InferCtxt<'tcx> { Ok(b) } StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_consts(relation, a, b) + relate::structurally_relate_consts(relation, a, b) } } } - _ => ty::relate::structurally_relate_consts(relation, a, b), + _ => relate::structurally_relate_consts(relation, a, b), } } @@ -303,7 +304,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { +pub trait ObligationEmittingRelation<'tcx>: TypeRelation> { fn span(&self) -> Span; fn param_env(&self) -> ty::ParamEnv<'tcx>; diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 225c126fcf819..5478afda455f0 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,15 +1,16 @@ use std::mem; use super::StructurallyRelateAliases; +use super::{ObligationEmittingRelation, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::type_variable::TypeVariableValue; -use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt}; @@ -228,7 +229,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Attempts to generalize `source_term` for the type variable `target_vid`. /// This checks for cycles -- that is, whether `source_term` references `target_vid`. - fn generalize> + Relate<'tcx>>( + fn generalize> + Relate>>( &self, span: Span, structurally_relate_aliases: StructurallyRelateAliases, @@ -395,7 +396,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { +impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -430,10 +431,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } #[instrument(level = "debug", skip(self, variance, b), ret)] - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -695,7 +696,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { _: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { let result = self.relate(a.skip_binder(), a.skip_binder())?; Ok(a.rebind(result)) diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index a224a86492ab4..98e8f07c7a213 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -1,6 +1,6 @@ //! Greatest lower bound. See [`lattice`]. -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Glb" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { // GLB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index d3001eb5838bb..cfce28aca5d6a 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -1,10 +1,10 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. +use super::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use crate::infer::InferCtxt; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index c0c51a2820b3d..f05b984142aee 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -21,7 +21,7 @@ use super::combine::ObligationEmittingRelation; use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; -use rustc_middle::ty::relate::RelateResult; +use super::RelateResult; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty}; diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 83ab77707709c..28dbaa94f95d3 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -6,7 +6,7 @@ use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Lub" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { // LUB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 86a01130167a5..627c527cba15f 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -1,6 +1,14 @@ //! This module contains the definitions of most `TypeRelation`s in the type system //! (except for some relations used for diagnostics and heuristics in the compiler). +//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). +pub use rustc_middle::ty::relate::*; + +pub use self::_match::MatchAgainstFreshVars; +pub use self::combine::CombineFields; +pub use self::combine::ObligationEmittingRelation; + +pub mod _match; pub(super) mod combine; mod generalize; mod glb; @@ -8,15 +16,3 @@ mod higher_ranked; mod lattice; mod lub; mod type_relating; - -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index e55a587882123..fd0bc9f44f753 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,12 +1,11 @@ use super::combine::CombineFields; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::{ - DefineOpaqueTypes, ObligationEmittingRelation, StructurallyRelateAliases, SubregionOrigin, -}; +use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_middle::ty::relate::{ - relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, +use super::{ + relate_args_invariantly, relate_args_with_variances, ObligationEmittingRelation, Relate, + RelateResult, StructurallyRelateAliases, TypeRelation, }; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,7 +28,7 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "TypeRelating" } @@ -56,10 +55,10 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { } } - fn relate_with_variance>( + fn relate_with_variance>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -226,7 +225,7 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate>, { if a == b { // Do nothing diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 5f9b870331c9a..886dbd317afa3 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -200,6 +200,12 @@ impl<'tcx> AdtDef<'tcx> { } } +impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { + fn def_id(self) -> DefId { + self.did() + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index dc13cc5437d56..cc1daeb641915 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -149,6 +149,10 @@ impl<'tcx> Const<'tcx> { } impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { + fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option { + self.try_to_target_usize(interner) + } + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self { Const::new_infer(tcx, infer) } @@ -168,6 +172,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self { Const::new_unevaluated(interner, uv) } + + fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { + Const::new_expr(interner, expr) + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f9a22aa72bee9..61d47eb1420bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -69,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; +use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; @@ -135,9 +136,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; type Clause = Clause<'tcx>; - type Clauses = ty::Clauses<'tcx>; + fn expand_abstract_consts>>(self, t: T) -> T { + self.expand_abstract_consts(t) + } + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } @@ -148,6 +152,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.generics_of(def_id) } + type VariancesOf = &'tcx [ty::Variance]; + + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + self.variances_of(def_id) + } + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of(def_id) } @@ -205,7 +215,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_args(args) } - fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs { + fn mk_args_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: CollectAndApply, + { self.mk_args_from_iter(args) } @@ -224,6 +238,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.arena.alloc(step) } + fn mk_type_list_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: CollectAndApply, + { + self.mk_type_list_from_iter(args) + } + fn parent(self, def_id: Self::DefId) -> Self::DefId { self.parent(def_id) } @@ -231,6 +253,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn recursion_limit(self) -> usize { self.recursion_limit().0 } + + type Features = &'tcx rustc_feature::Features; + + fn features(self) -> Self::Features { + self.features() + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { @@ -249,6 +277,12 @@ impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { } } +impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_feature::Features { + fn generic_const_exprs(self) -> bool { + self.generic_const_exprs + } +} + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 131c62d6d19ff..7ff1b79982274 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,6 +60,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; use tracing::{debug, instrument}; pub use vtable::*; @@ -114,7 +115,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -122,7 +123,6 @@ pub use self::typeck_results::{ TypeckResults, UserType, UserTypeAnnotationIndex, }; -pub mod _match; pub mod abstract_const; pub mod adjustment; pub mod cast; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index e24e64b23013a..b169d672a8468 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -1,383 +1,54 @@ -//! Generalized type relating mechanism. -//! -//! A type relation `R` relates a pair of values `(A, B)`. `A and B` are usually -//! types or regions but can be other things. Examples of type relations are -//! subtyping, type equality, etc. +use std::iter; -use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::{ - self, ExistentialPredicate, ExistentialPredicateStableCmpExt as _, GenericArg, GenericArgKind, - GenericArgsRef, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable, -}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_macros::TypeVisitable; use rustc_target::spec::abi; -use std::iter; -use tracing::{debug, instrument}; - -use super::Pattern; - -pub type RelateResult<'tcx, T> = Result>; - -pub trait TypeRelation<'tcx>: Sized { - fn tcx(&self) -> TyCtxt<'tcx>; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; - - /// Generic relation routine suitable for most anything. - fn relate>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> { - Relate::relate(self, a, b) - } - - /// Relate the two args for the given item. The default - /// is to look up the variance for the item and proceed - /// accordingly. - fn relate_item_args( - &mut self, - item_def_id: DefId, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - debug!( - "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", - item_def_id, a_arg, b_arg - ); - - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) - } - - /// Switch variance for the purpose of relating `a` and `b`. - fn relate_with_variance>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T>; - - // Overridable relations. You shouldn't typically call these - // directly, instead call `relate()`, which in turn calls - // these. This is both more uniform but also allows us to add - // additional hooks for other types in the future if needed - // without making older code, which called `relate`, obsolete. - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>>; - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>>; - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>; -} - -pub trait Relate<'tcx>: TypeFoldable> + PartialEq + Copy { - fn relate>( - relation: &mut R, - a: Self, - b: Self, - ) -> RelateResult<'tcx, Self>; -} - -/////////////////////////////////////////////////////////////////////////// -// Relate impls - -#[inline] -pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { - relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b) - })) -} - -pub fn relate_args_with_variances<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - ty_def_id: DefId, - variances: &[ty::Variance], - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - fetch_ty_for_diag: bool, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - let tcx = relation.tcx(); - - let mut cached_ty = None; - let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { - let variance = variances[i]; - let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = - *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg)); - ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } - } else { - ty::VarianceDiagInfo::default() - }; - relation.relate_with_variance(variance, variance_info, a, b) - }); - - tcx.mk_args_from_iter(params) -} - -impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { - fn relate>( - relation: &mut R, - a: ty::FnSig<'tcx>, - b: ty::FnSig<'tcx>, - ) -> RelateResult<'tcx, ty::FnSig<'tcx>> { - let tcx = relation.tcx(); - - if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic))); - } - let safety = relation.relate(a.safety, b.safety)?; - let abi = relation.relate(a.abi, b.abi)?; - - if a.inputs().len() != b.inputs().len() { - return Err(TypeError::ArgCount); - } +pub use rustc_type_ir::relate::*; - let inputs_and_output = iter::zip(a.inputs(), b.inputs()) - .map(|(&a, &b)| ((a, b), false)) - .chain(iter::once(((a.output(), b.output()), true))) - .map(|((a, b), is_output)| { - if is_output { - relation.relate(a, b) - } else { - relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a, - b, - ) - } - }) - .enumerate() - .map(|(i, r)| match r { - Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { - Err(TypeError::ArgumentSorts(exp_found, i)) - } - Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { - Err(TypeError::ArgumentMutability(i)) - } - r => r, - }); - Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, - c_variadic: a.c_variadic, - safety, - abi, - }) - } -} - -impl<'tcx> Relate<'tcx> for ty::BoundConstness { - fn relate>( - _relation: &mut R, - a: ty::BoundConstness, - b: ty::BoundConstness, - ) -> RelateResult<'tcx, ty::BoundConstness> { - if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for hir::Safety { - fn relate>( - _relation: &mut R, - a: hir::Safety, - b: hir::Safety, - ) -> RelateResult<'tcx, hir::Safety> { - if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for abi::Abi { - fn relate>( - _relation: &mut R, - a: abi::Abi, - b: abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) } - } -} - -impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { - fn relate>( - relation: &mut R, - a: ty::AliasTy<'tcx>, - b: ty::AliasTy<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTy<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::Opaque => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::Projection | ty::Weak | ty::Inherent => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::AliasTerm<'tcx> { - fn relate>( - relation: &mut R, - a: ty::AliasTerm<'tcx>, - b: ty::AliasTerm<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTerm<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::AliasTermKind::OpaqueTy => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { - fn relate>( - relation: &mut R, - a: ty::ExistentialProjection<'tcx>, - b: ty::ExistentialProjection<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let term = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.term, - b.term, - )?; - let args = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.args, - b.args, - )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { - fn relate>( - relation: &mut R, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { - fn relate>( - relation: &mut R, - a: ty::ExistentialTraitRef<'tcx>, - b: ty::ExistentialTraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) - } - } -} +use crate::ty::error::{ExpectedFound, TypeError}; +use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; +use crate::ty::{self as ty, Ty, TyCtxt}; -#[derive(PartialEq, Copy, Debug, Clone, TypeFoldable, TypeVisitable)] -struct CoroutineWitness<'tcx>(&'tcx ty::List>); +pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult, T>; -impl<'tcx> Relate<'tcx> for CoroutineWitness<'tcx> { - fn relate>( - relation: &mut R, - a: CoroutineWitness<'tcx>, - b: CoroutineWitness<'tcx>, - ) -> RelateResult<'tcx, CoroutineWitness<'tcx>> { - assert_eq!(a.0.len(), b.0.len()); - let tcx = relation.tcx(); - let types = - tcx.mk_type_list_from_iter(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; - Ok(CoroutineWitness(types)) - } +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, } -impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> { +impl<'tcx> Relate> for ty::ImplSubject<'tcx> { #[inline] - fn relate>( + fn relate>>( relation: &mut R, - a: ImplSubject<'tcx>, - b: ImplSubject<'tcx>, - ) -> RelateResult<'tcx, ImplSubject<'tcx>> { + a: ty::ImplSubject<'tcx>, + b: ty::ImplSubject<'tcx>, + ) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> { match (a, b) { - (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { + (ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => { let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?; - Ok(ImplSubject::Trait(trait_ref)) + Ok(ty::ImplSubject::Trait(trait_ref)) } - (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { + (ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => { let ty = Ty::relate(relation, ty_a, ty_b)?; - Ok(ImplSubject::Inherent(ty)) + Ok(ty::ImplSubject::Inherent(ty)) } - (ImplSubject::Trait(_), ImplSubject::Inherent(_)) - | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { + (ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_)) + | (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => { bug!("can not relate TraitRef and Ty"); } } } } -impl<'tcx> Relate<'tcx> for Ty<'tcx> { +impl<'tcx> Relate> for Ty<'tcx> { #[inline] - fn relate>( + fn relate>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, @@ -386,9 +57,9 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } -impl<'tcx> Relate<'tcx> for Pattern<'tcx> { +impl<'tcx> Relate> for ty::Pattern<'tcx> { #[inline] - fn relate>( + fn relate>>( relation: &mut R, a: Self, b: Self, @@ -416,276 +87,8 @@ impl<'tcx> Relate<'tcx> for Pattern<'tcx> { } } -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of projections, and inference variables have to be -/// handled by the caller. -#[instrument(level = "trace", skip(relation), ret)] -pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> { - let tcx = relation.tcx(); - match (a.kind(), b.kind()) { - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_tys") - } - - (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in structurally_relate_tys") - } - - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), - - (&ty::Never, _) - | (&ty::Char, _) - | (&ty::Bool, _) - | (&ty::Int(_), _) - | (&ty::Uint(_), _) - | (&ty::Float(_), _) - | (&ty::Str, _) - if a == b => - { - Ok(a) - } - - (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - Ok(a) - } - - (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), - - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) if a_def == b_def => { - let args = relation.relate_item_args(a_def.did(), a_args, b_args)?; - Ok(Ty::new_adt(tcx, a_def, args)) - } - - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), - - (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) - if a_repr == b_repr => - { - Ok(Ty::new_dynamic( - tcx, - relation.relate(a_obj, b_obj)?, - relation.relate(a_region, b_region)?, - a_repr, - )) - } - - (&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => { - // All Coroutine types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine(tcx, a_id, args)) - } - - (&ty::CoroutineWitness(a_id, a_args), &ty::CoroutineWitness(b_id, b_args)) - if a_id == b_id => - { - // All CoroutineWitness types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_witness(tcx, a_id, args)) - } - - (&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => { - // All Closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_closure(tcx, a_id, args)) - } - - (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args)) - if a_id == b_id => - { - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_closure(tcx, a_id, args)) - } - - (&ty::RawPtr(a_ty, a_mutbl), &ty::RawPtr(b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ptr(tcx, ty, a_mutbl)) - } - - (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let r = relation.relate(a_r, b_r)?; - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) - } - - (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { - let t = relation.relate(a_t, b_t)?; - match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), - Err(err) => { - // Check whether the lengths are both concrete/known values, - // but are unequal, for better diagnostics. - let sz_a = sz_a.try_to_target_usize(tcx); - let sz_b = sz_b.try_to_target_usize(tcx); - - match (sz_a, sz_b) { - (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => { - Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val))) - } - _ => Err(err), - } - } - } - } - - (&ty::Slice(a_t), &ty::Slice(b_t)) => { - let t = relation.relate(a_t, b_t)?; - Ok(Ty::new_slice(tcx, t)) - } - - (&ty::Tuple(as_), &ty::Tuple(bs)) => { - if as_.len() == bs.len() { - Ok(Ty::new_tup_from_iter( - tcx, - iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), - )?) - } else if !(as_.is_empty() || bs.is_empty()) { - Err(TypeError::TupleSize(expected_found(as_.len(), bs.len()))) - } else { - Err(TypeError::Sorts(expected_found(a, b))) - } - } - - (&ty::FnDef(a_def_id, a_args), &ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { - let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(tcx, a_def_id, args)) - } - - (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { - let fty = relation.relate(a_fty, b_fty)?; - Ok(Ty::new_fn_ptr(tcx, fty)) - } - - // Alias tend to mostly already be handled downstream due to normalization. - (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { - let alias_ty = relation.relate(a_data, b_data)?; - assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) - } - - (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => { - let ty = relation.relate(a_ty, b_ty)?; - let pat = relation.relate(a_pat, b_pat)?; - Ok(Ty::new_pat(tcx, ty, pat)) - } - - _ => Err(TypeError::Sorts(expected_found(a, b))), - } -} - -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of unevaluated consts, and inference variables have -/// to be handled by the caller. -/// -/// FIXME: This is not totally structual, which probably should be fixed. -/// See the HACKs below. -pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - mut a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, -) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); - let tcx = relation.tcx(); - - if tcx.features().generic_const_exprs { - a = tcx.expand_abstract_consts(a); - b = tcx.expand_abstract_consts(b); - } - - debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); - - // Currently, the values that can be unified are primitive types, - // and those that derive both `PartialEq` and `Eq`, corresponding - // to structural-match types. - let is_match = match (a.kind(), b.kind()) { - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) - } - - (ty::ConstKind::Error(_), _) => return Ok(a), - (_, ty::ConstKind::Error(_)) => return Ok(b), - - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - true - } - (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, - - // While this is slightly incorrect, it shouldn't matter for `min_const_generics` - // and is the better alternative to waiting until `generic_const_exprs` can - // be stabilized. - (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { - if cfg!(debug_assertions) { - let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args); - let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args); - assert_eq!(a_ty, b_ty); - } - - let args = relation.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - au.args, - bu.args, - )?; - return Ok(ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); - } - (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { - match (ae.kind, be.kind) { - (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) - if a_binop == b_binop => {} - (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {} - (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {} - (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {} - _ => return Err(TypeError::ConstMismatch(expected_found(a, b))), - } - - let args = relation.relate(ae.args(), be.args())?; - return Ok(ty::Const::new_expr(tcx, ty::Expr::new(ae.kind, args))); - } - _ => false, - }; - if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) } -} - -impl<'tcx> Relate<'tcx> for &'tcx ty::List> { - fn relate>( +impl<'tcx> Relate> for &'tcx ty::List> { + fn relate>>( relation: &mut R, a: Self, b: Self, @@ -703,44 +106,65 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { - return Err(TypeError::ExistentialMismatch(expected_found(a, b))); + return Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))); } let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { match (ep_a.skip_binder(), ep_b.skip_binder()) { - (ExistentialPredicate::Trait(a), ExistentialPredicate::Trait(b)) => Ok(ep_a - .rebind(ExistentialPredicate::Trait( - relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), - ))), - (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => { - Ok(ep_a.rebind(ExistentialPredicate::Projection( + (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { + Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), ))) } - (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) - if a == b => - { - Ok(ep_a.rebind(ExistentialPredicate::AutoTrait(a))) - } - _ => Err(TypeError::ExistentialMismatch(expected_found(a, b))), + ( + ty::ExistentialPredicate::Projection(a), + ty::ExistentialPredicate::Projection(b), + ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + ( + ty::ExistentialPredicate::AutoTrait(a), + ty::ExistentialPredicate::AutoTrait(b), + ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), + _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))), } }); tcx.mk_poly_existential_predicates_from_iter(v) } } -impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { - fn relate>( +impl<'tcx> Relate> for hir::Safety { + fn relate>>( + _relation: &mut R, + a: hir::Safety, + b: hir::Safety, + ) -> RelateResult<'tcx, hir::Safety> { + if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) } + } +} + +impl<'tcx> Relate> for abi::Abi { + fn relate>>( + _relation: &mut R, + a: abi::Abi, + b: abi::Abi, + ) -> RelateResult<'tcx, abi::Abi> { + if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) } + } +} + +impl<'tcx> Relate> for ty::GenericArgsRef<'tcx> { + fn relate>>( relation: &mut R, - a: GenericArgsRef<'tcx>, - b: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { + a: ty::GenericArgsRef<'tcx>, + b: ty::GenericArgsRef<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { relate_args_invariantly(relation, a, b) } } -impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { - fn relate>( +impl<'tcx> Relate> for ty::Region<'tcx> { + fn relate>>( relation: &mut R, a: ty::Region<'tcx>, b: ty::Region<'tcx>, @@ -749,8 +173,8 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { - fn relate>( +impl<'tcx> Relate> for ty::Const<'tcx> { + fn relate>>( relation: &mut R, a: ty::Const<'tcx>, b: ty::Const<'tcx>, @@ -759,85 +183,70 @@ impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> { - fn relate>( - relation: &mut R, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> { - relation.binders(a, b) +impl<'tcx> Relate> for ty::Expr<'tcx> { + fn relate>>( + relation: &mut R, + ae: ty::Expr<'tcx>, + be: ty::Expr<'tcx>, + ) -> RelateResult<'tcx, ty::Expr<'tcx>> { + // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical + // exprs? Should we care about that? + // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to + // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought + // of as being generic over the argument types, however this is implicit so these types don't get + // related when we relate the args of the item this const arg is for. + match (ae.kind, be.kind) { + (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {} + (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {} + (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {} + (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {} + _ => return Err(TypeError::Mismatch), + } + + let args = relation.relate(ae.args(), be.args())?; + Ok(ty::Expr::new(ae.kind, args)) } } -impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { - fn relate>( +impl<'tcx> Relate> for ty::GenericArg<'tcx> { + fn relate>>( relation: &mut R, - a: GenericArg<'tcx>, - b: GenericArg<'tcx>, - ) -> RelateResult<'tcx, GenericArg<'tcx>> { + a: ty::GenericArg<'tcx>, + b: ty::GenericArg<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> { match (a.unpack(), b.unpack()) { - (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { + (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => { Ok(relation.relate(a_lt, b_lt)?.into()) } - (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { + (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => { Ok(relation.relate(a_ty, b_ty)?.into()) } - (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { + (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } - (GenericArgKind::Lifetime(unpacked), x) => { + (ty::GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Type(unpacked), x) => { + (ty::GenericArgKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Const(unpacked), x) => { + (ty::GenericArgKind::Const(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } } } } -impl<'tcx> Relate<'tcx> for ty::PredicatePolarity { - fn relate>( - _relation: &mut R, - a: ty::PredicatePolarity, - b: ty::PredicatePolarity, - ) -> RelateResult<'tcx, ty::PredicatePolarity> { - if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { - fn relate>( - relation: &mut R, - a: ty::TraitPredicate<'tcx>, - b: ty::TraitPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { - Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, - polarity: relation.relate(a.polarity, b.polarity)?, - }) - } -} - -impl<'tcx> Relate<'tcx> for Term<'tcx> { - fn relate>( +impl<'tcx> Relate> for ty::Term<'tcx> { + fn relate>>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { Ok(match (a.unpack(), b.unpack()) { - (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), - (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } } - -/////////////////////////////////////////////////////////////////////////// -// Error handling - -pub fn expected_found(a: T, b: T) -> ExpectedFound { - ExpectedFound::new(true, a, b) -} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c83f6b0b9ec6d..ba9ed0d5b70a6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -810,6 +810,31 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_alias(interner, kind, alias_ty) } + fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Ty::new_error(interner, guar) + } + + fn new_adt( + interner: TyCtxt<'tcx>, + adt_def: ty::AdtDef<'tcx>, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_adt(interner, adt_def, args) + } + + fn new_foreign(interner: TyCtxt<'tcx>, def_id: DefId) -> Self { + Ty::new_foreign(interner, def_id) + } + + fn new_dynamic( + interner: TyCtxt<'tcx>, + preds: &'tcx List>, + region: ty::Region<'tcx>, + kind: ty::DynKind, + ) -> Self { + Ty::new_dynamic(interner, preds, region, kind) + } + fn new_coroutine( interner: TyCtxt<'tcx>, def_id: DefId, @@ -818,6 +843,51 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { Ty::new_coroutine(interner, def_id, args) } + fn new_coroutine_closure( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_closure(interner, def_id, args) + } + + fn new_closure(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_closure(interner, def_id, args) + } + + fn new_coroutine_witness( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_witness(interner, def_id, args) + } + + fn new_ptr(interner: TyCtxt<'tcx>, ty: Self, mutbl: hir::Mutability) -> Self { + Ty::new_ptr(interner, ty, mutbl) + } + + fn new_ref( + interner: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ty: Self, + mutbl: hir::Mutability, + ) -> Self { + Ty::new_ref(interner, region, ty, mutbl) + } + + fn new_array_with_const_len(interner: TyCtxt<'tcx>, ty: Self, len: ty::Const<'tcx>) -> Self { + Ty::new_array_with_const_len(interner, ty, len) + } + + fn new_slice(interner: TyCtxt<'tcx>, ty: Self) -> Self { + Ty::new_slice(interner, ty) + } + + fn new_tup(interner: TyCtxt<'tcx>, tys: &[Ty<'tcx>]) -> Self { + Ty::new_tup(interner, tys) + } + fn new_tup_from_iter(interner: TyCtxt<'tcx>, iter: It) -> T::Output where It: Iterator, @@ -844,6 +914,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { ) -> Self { Ty::from_coroutine_closure_kind(interner, kind) } + + fn new_fn_def(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_fn_def(interner, def_id, args) + } + + fn new_fn_ptr(interner: TyCtxt<'tcx>, sig: ty::Binder<'tcx, ty::FnSig<'tcx>>) -> Self { + Ty::new_fn_ptr(interner, sig) + } + + fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self { + Ty::new_pat(interner, ty, pat) + } } /// Type utilities @@ -1812,43 +1894,6 @@ impl<'tcx> rustc_type_ir::inherent::Tys> for &'tcx ty::List { - /// No additional information - this is the default. - /// We will not add any additional information to error messages. - #[default] - None, - /// We switched our variance because a generic argument occurs inside - /// the invariant generic argument of another type. - Invariant { - /// The generic type containing the generic parameter - /// that changes the variance (e.g. `*mut T`, `MyStruct`) - ty: Ty<'tcx>, - /// The index of the generic parameter being used - /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) - param_index: u32, - }, -} - -impl<'tcx> VarianceDiagInfo<'tcx> { - /// Mirrors `Variance::xform` - used to 'combine' the existing - /// and new `VarianceDiagInfo`s when our variance changes. - pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { - // For now, just use the first `VarianceDiagInfo::Invariant` that we see - match self { - VarianceDiagInfo::None => other, - VarianceDiagInfo::Invariant { .. } => self, - } - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 8bcc21d82f85b..c30d21fd7843d 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -4,13 +4,16 @@ version = "0.0.0" edition = "2021" [dependencies] -rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +# tidy-alphabetical-start derivative = "2.2.0" +rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } rustc_serialize = { path = "../rustc_serialize", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } -rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } +rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +tracing = "0.1" +# tidy-alphabetical-end [features] default = ["nightly"] diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 92e05cc4901ae..5c00b6978d695 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -7,11 +7,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver< - 'a, +pub struct EagerResolver<'a, Infcx, I = ::Interner> +where Infcx: InferCtxtLike, - I: Interner = ::Interner, -> { + I: Interner, +{ infcx: &'a Infcx, } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index f90e47110376c..b522022c20674 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -37,11 +37,11 @@ pub(super) mod canonical; mod probe; mod select; -pub struct EvalCtxt< - 'a, +pub struct EvalCtxt<'a, Infcx, I = ::Interner> +where Infcx: InferCtxtLike, - I: Interner = ::Interner, -> { + I: Interner, +{ /// The inference context that backs (mostly) inference and placeholder terms /// instantiated while solving goals. /// diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9e6ae91251503..4a935f4a64a0f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::relate::MatchAgainstFreshVars; +use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::DefineOpaqueTypes; @@ -40,11 +42,9 @@ use rustc_middle::bug; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 94874a6acfcef..205a1e5f100e7 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -7,7 +7,10 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; +use rustc_ast_ir::Mutability; + use crate::fold::{TypeFoldable, TypeSuperFoldable}; +use crate::relate::Relate; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom}; @@ -21,6 +24,7 @@ pub trait Ty>: + IntoKind> + TypeSuperVisitable + TypeSuperFoldable + + Relate + Flags { fn new_bool(interner: I) -> Self; @@ -35,8 +39,37 @@ pub trait Ty>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; + + fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; + + fn new_foreign(interner: I, def_id: I::DefId) -> Self; + + fn new_dynamic( + interner: I, + preds: I::BoundExistentialPredicates, + region: I::Region, + kind: ty::DynKind, + ) -> Self; + fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_ptr(interner: I, ty: Self, mutbl: Mutability) -> Self; + + fn new_ref(interner: I, region: I::Region, ty: Self, mutbl: Mutability) -> Self; + + fn new_array_with_const_len(interner: I, ty: Self, len: I::Const) -> Self; + + fn new_slice(interner: I, ty: Self) -> Self; + + fn new_tup(interner: I, tys: &[I::Ty]) -> Self; + fn new_tup_from_iter(interner: I, iter: It) -> T::Output where It: Iterator, @@ -49,6 +82,12 @@ pub trait Ty>: fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; + + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; } pub trait Tys>: @@ -84,6 +123,7 @@ pub trait Region>: + IntoKind> + Flags + TypeVisitable + + Relate { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -102,8 +142,11 @@ pub trait Const>: + IntoKind> + TypeSuperVisitable + TypeSuperFoldable + + Relate + Flags { + fn try_to_target_usize(self, interner: I) -> Option; + fn new_infer(interner: I, var: ty::InferConst) -> Self; fn new_var(interner: I, var: ty::ConstVid) -> Self; @@ -113,6 +156,8 @@ pub trait Const>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; + + fn new_expr(interner: I, expr: I::ExprConst) -> Self; } pub trait GenericsOf> { @@ -128,13 +173,14 @@ pub trait GenericArgs>: + Deref> + Default + TypeFoldable + + Relate { fn type_at(self, i: usize) -> I::Ty; fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; fn extend_with_error( - tcx: I, + interner: I, def_id: I::DefId, original_args: &[I::GenericArg], ) -> I::GenericArgs; @@ -193,3 +239,11 @@ pub trait BoundVarLike { pub trait ParamLike { fn index(self) -> u32; } + +pub trait AdtDef: Copy + Debug + Hash + Eq { + fn def_id(self) -> I::DefId; +} + +pub trait Features: Copy { + fn generic_const_exprs(self) -> bool; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6ebb434299b30..ad1d2753b2822 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,6 +6,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, DebugWithInfcx}; @@ -25,8 +26,8 @@ pub trait Interner: + IrPrint> + IrPrint> { - type DefId: Copy + Debug + Hash + Eq + TypeVisitable; - type AdtDef: Copy + Debug + Hash + Eq; + type DefId: Copy + Debug + Hash + Eq + TypeFoldable; + type AdtDef: AdtDef; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; @@ -35,8 +36,15 @@ pub trait Interner: + Hash + Eq + IntoKind> - + TypeVisitable; - type Term: Copy + Debug + Hash + Eq + IntoKind> + TypeVisitable; + + TypeVisitable + + Relate; + type Term: Copy + + Debug + + Hash + + Eq + + IntoKind> + + TypeFoldable + + Relate; type BoundVarKinds: Copy + Debug @@ -66,11 +74,11 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + DebugWithInfcx + Hash + Eq; + type BoundExistentialPredicates: Copy + DebugWithInfcx + Hash + Eq + Relate; type AllocId: Copy + Debug + Hash + Eq; - type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx; - type Safety: Safety; - type Abi: Abi; + type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx + Relate; + type Safety: Safety + TypeFoldable + Relate; + type Abi: Abi + TypeFoldable + Relate; // Kinds of consts type Const: Const; @@ -78,7 +86,7 @@ pub trait Interner: type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike; type ValueConst: Copy + Debug + Hash + Eq; - type ExprConst: Copy + DebugWithInfcx + Hash + Eq; + type ExprConst: Copy + DebugWithInfcx + Hash + Eq + Relate; // Kinds of regions type Region: Region; @@ -93,11 +101,16 @@ pub trait Interner: type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; + fn expand_abstract_consts>(self, t: T) -> T; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + type VariancesOf: Copy + Debug + Deref; + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; + // FIXME: Remove after uplifting `EarlyBinder` fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; @@ -112,7 +125,12 @@ pub trait Interner: ) -> (ty::TraitRef, Self::GenericArgsSlice); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; + + fn mk_args_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: CollectAndApply; + fn check_and_mk_args( self, def_id: Self::DefId, @@ -124,9 +142,17 @@ pub trait Interner: step: CanonicalGoalEvaluationStep, ) -> Self::CanonicalGoalEvaluationStepRef; + fn mk_type_list_from_iter(self, args: I) -> T::Output + where + I: Iterator, + T: CollectAndApply; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize; + + type Features: Features; + fn features(self) -> Self::Features; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 7d363daa420ab..7371646893035 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -31,6 +31,7 @@ pub mod fold; pub mod inherent; pub mod ir_print; pub mod lift; +pub mod relate; pub mod solve; // These modules are not `pub` since they are glob-imported. diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs new file mode 100644 index 0000000000000..cae1d13020d34 --- /dev/null +++ b/compiler/rustc_type_ir/src/relate.rs @@ -0,0 +1,666 @@ +use std::iter; + +use rustc_ast_ir::Mutability; +use rustc_type_ir::error::{ExpectedFound, TypeError}; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::{debug, instrument}; + +pub type RelateResult = Result>; + +/// Extra information about why we ended up with a particular variance. +/// This is only used to add more information to error messages, and +/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` +/// may lead to confusing notes in error messages, it will never cause +/// a miscompilation or unsoundness. +/// +/// When in doubt, use `VarianceDiagInfo::default()` +#[derive(derivative::Derivative)] +#[derivative( + Copy(bound = ""), + Clone(bound = ""), + Debug(bound = ""), + Default(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub enum VarianceDiagInfo { + /// No additional information - this is the default. + /// We will not add any additional information to error messages. + #[derivative(Default)] + None, + /// We switched our variance because a generic argument occurs inside + /// the invariant generic argument of another type. + Invariant { + /// The generic type containing the generic parameter + /// that changes the variance (e.g. `*mut T`, `MyStruct`) + ty: I::Ty, + /// The index of the generic parameter being used + /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) + param_index: u32, + }, +} + +impl VarianceDiagInfo { + /// Mirrors `Variance::xform` - used to 'combine' the existing + /// and new `VarianceDiagInfo`s when our variance changes. + pub fn xform(self, other: VarianceDiagInfo) -> VarianceDiagInfo { + // For now, just use the first `VarianceDiagInfo::Invariant` that we see + match self { + VarianceDiagInfo::None => other, + VarianceDiagInfo::Invariant { .. } => self, + } + } +} + +pub trait TypeRelation: Sized { + fn tcx(&self) -> I; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Generic relation routine suitable for most anything. + fn relate>(&mut self, a: T, b: T) -> RelateResult { + Relate::relate(self, a, b) + } + + /// Relate the two args for the given item. The default + /// is to look up the variance for the item and proceed + /// accordingly. + fn relate_item_args( + &mut self, + item_def_id: I::DefId, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + ) -> RelateResult { + debug!( + "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", + item_def_id, a_arg, b_arg + ); + + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_args_with_variances(self, item_def_id, &opt_variances, a_arg, b_arg, true) + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance>( + &mut self, + variance: ty::Variance, + info: VarianceDiagInfo, + a: T, + b: T, + ) -> RelateResult; + + // Overridable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult; + + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult; + + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult; + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult> + where + T: Relate; +} + +pub trait Relate: TypeFoldable + PartialEq + Copy { + fn relate>(relation: &mut R, a: Self, b: Self) -> RelateResult; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +#[inline] +pub fn relate_args_invariantly>( + relation: &mut R, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, +) -> RelateResult { + relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { + relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b) + })) +} + +pub fn relate_args_with_variances>( + relation: &mut R, + ty_def_id: I::DefId, + variances: &[ty::Variance], + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + fetch_ty_for_diag: bool, +) -> RelateResult { + let tcx = relation.tcx(); + + let mut cached_ty = None; + let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { + let variance = variances[i]; + let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag { + let ty = + *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg)); + VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } + } else { + VarianceDiagInfo::default() + }; + relation.relate_with_variance(variance, variance_info, a, b) + }); + + tcx.mk_args_from_iter(params) +} + +impl Relate for ty::FnSig { + fn relate>( + relation: &mut R, + a: ty::FnSig, + b: ty::FnSig, + ) -> RelateResult> { + let tcx = relation.tcx(); + + if a.c_variadic != b.c_variadic { + return Err(TypeError::VariadicMismatch({ + let a = a.c_variadic; + let b = b.c_variadic; + ExpectedFound::new(true, a, b) + })); + } + let safety = relation.relate(a.safety, b.safety)?; + let abi = relation.relate(a.abi, b.abi)?; + + let a_inputs = a.inputs(); + let b_inputs = b.inputs(); + + if a_inputs.len() != b_inputs.len() { + return Err(TypeError::ArgCount); + } + + let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter()) + .map(|(&a, &b)| ((a, b), false)) + .chain(iter::once(((a.output(), b.output()), true))) + .map(|((a, b), is_output)| { + if is_output { + relation.relate(a, b) + } else { + relation.relate_with_variance( + ty::Variance::Contravariant, + VarianceDiagInfo::default(), + a, + b, + ) + } + }) + .enumerate() + .map(|(i, r)| match r { + Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { + Err(TypeError::ArgumentSorts(exp_found, i)) + } + Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { + Err(TypeError::ArgumentMutability(i)) + } + r => r, + }); + Ok(ty::FnSig { + inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, + c_variadic: a.c_variadic, + safety, + abi, + }) + } +} + +impl Relate for ty::BoundConstness { + fn relate>( + _relation: &mut R, + a: ty::BoundConstness, + b: ty::BoundConstness, + ) -> RelateResult { + if a != b { + Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl Relate for ty::AliasTy { + fn relate>( + relation: &mut R, + a: ty::AliasTy, + b: ty::AliasTy, + ) -> RelateResult> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::Opaque => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::Projection | ty::Weak | ty::Inherent => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl Relate for ty::AliasTerm { + fn relate>( + relation: &mut R, + a: ty::AliasTerm, + b: ty::AliasTerm, + ) -> RelateResult> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::AliasTermKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl Relate for ty::ExistentialProjection { + fn relate>( + relation: &mut R, + a: ty::ExistentialProjection, + b: ty::ExistentialProjection, + ) -> RelateResult> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let term = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.term, + b.term, + )?; + let args = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.args, + b.args, + )?; + Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + } + } +} + +impl Relate for ty::TraitRef { + fn relate>( + relation: &mut R, + a: ty::TraitRef, + b: ty::TraitRef, + ) -> RelateResult> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl Relate for ty::ExistentialTraitRef { + fn relate>( + relation: &mut R, + a: ty::ExistentialTraitRef, + b: ty::ExistentialTraitRef, + ) -> RelateResult> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + } + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of projections, and inference variables have to be +/// handled by the caller. +#[instrument(level = "trace", skip(relation), ret)] +pub fn structurally_relate_tys>( + relation: &mut R, + a: I::Ty, + b: I::Ty, +) -> RelateResult { + let tcx = relation.tcx(); + match (a.kind(), b.kind()) { + (ty::Infer(_), _) | (_, ty::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_tys") + } + + (ty::Bound(..), _) | (_, ty::Bound(..)) => { + panic!("bound types encountered in structurally_relate_tys") + } + + (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), + + (ty::Never, _) + | (ty::Char, _) + | (ty::Bool, _) + | (ty::Int(_), _) + | (ty::Uint(_), _) + | (ty::Float(_), _) + | (ty::Str, _) + if a == b => + { + Ok(a) + } + + (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + //debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name"); + Ok(a) + } + + (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), + + (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { + let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; + Ok(Ty::new_adt(tcx, a_def, args)) + } + + (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), + + (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { + Ok(Ty::new_dynamic( + tcx, + relation.relate(a_obj, b_obj)?, + relation.relate(a_region, b_region)?, + a_repr, + )) + } + + (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => { + // All Coroutine types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine(tcx, a_id, args)) + } + + (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args)) + if a_id == b_id => + { + // All CoroutineWitness types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_witness(tcx, a_id, args)) + } + + (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => { + // All Closure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_closure(tcx, a_id, args)) + } + + (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args)) + if a_id == b_id => + { + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + } + + (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ptr(tcx, ty, a_mutbl)) + } + + (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let r = relation.relate(a_r, b_r)?; + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) + } + + (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => { + let t = relation.relate(a_t, b_t)?; + match relation.relate(sz_a, sz_b) { + Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), + Err(err) => { + // Check whether the lengths are both concrete/known values, + // but are unequal, for better diagnostics. + let sz_a = sz_a.try_to_target_usize(tcx); + let sz_b = sz_b.try_to_target_usize(tcx); + + match (sz_a, sz_b) { + (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( + TypeError::FixedArraySize(ExpectedFound::new(true, sz_a_val, sz_b_val)), + ), + _ => Err(err), + } + } + } + } + + (ty::Slice(a_t), ty::Slice(b_t)) => { + let t = relation.relate(a_t, b_t)?; + Ok(Ty::new_slice(tcx, t)) + } + + (ty::Tuple(as_), ty::Tuple(bs)) => { + if as_.len() == bs.len() { + Ok(Ty::new_tup_from_iter( + tcx, + iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), + )?) + } else if !(as_.is_empty() || bs.is_empty()) { + Err(TypeError::TupleSize(ExpectedFound::new(true, as_.len(), bs.len()))) + } else { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + } + + (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { + let args = relation.relate_item_args(a_def_id, a_args, b_args)?; + Ok(Ty::new_fn_def(tcx, a_def_id, args)) + } + + (ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => { + let fty = relation.relate(a_fty, b_fty)?; + Ok(Ty::new_fn_ptr(tcx, fty)) + } + + // Alias tend to mostly already be handled downstream due to normalization. + (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => { + let alias_ty = relation.relate(a_data, b_data)?; + assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + } + + (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => { + let ty = relation.relate(a_ty, b_ty)?; + let pat = relation.relate(a_pat, b_pat)?; + Ok(Ty::new_pat(tcx, ty, pat)) + } + + _ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))), + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of unevaluated consts, and inference variables have +/// to be handled by the caller. +/// +/// FIXME: This is not totally structual, which probably should be fixed. +/// See the HACKs below. +pub fn structurally_relate_consts>( + relation: &mut R, + mut a: I::Const, + mut b: I::Const, +) -> RelateResult { + debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); + let tcx = relation.tcx(); + + if tcx.features().generic_const_exprs() { + a = tcx.expand_abstract_consts(a); + b = tcx.expand_abstract_consts(b); + } + + debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + + // Currently, the values that can be unified are primitive types, + // and those that derive both `PartialEq` and `Eq`, corresponding + // to structural-match types. + let is_match = match (a.kind(), b.kind()) { + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) + } + + (ty::ConstKind::Error(_), _) => return Ok(a), + (_, ty::ConstKind::Error(_)) => return Ok(b), + + (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + // debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); + true + } + (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, + (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `generic_const_exprs` can + // be stabilized. + (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { + if cfg!(debug_assertions) { + let a_ty = tcx.type_of(au.def).instantiate(tcx, &au.args); + let b_ty = tcx.type_of(bu.def).instantiate(tcx, &bu.args); + assert_eq!(a_ty, b_ty); + } + + let args = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + au.args, + bu.args, + )?; + return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); + } + (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { + let expr = relation.relate(ae, be)?; + return Ok(Const::new_expr(tcx, expr)); + } + _ => false, + }; + if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))) } +} + +impl> Relate for ty::Binder { + fn relate>( + relation: &mut R, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult> { + relation.binders(a, b) + } +} + +impl Relate for ty::PredicatePolarity { + fn relate>( + _relation: &mut R, + a: ty::PredicatePolarity, + b: ty::PredicatePolarity, + ) -> RelateResult { + if a != b { + Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl Relate for ty::TraitPredicate { + fn relate>( + relation: &mut R, + a: ty::TraitPredicate, + b: ty::TraitPredicate, + ) -> RelateResult> { + Ok(ty::TraitPredicate { + trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, + polarity: relation.relate(a.polarity, b.polarity)?, + }) + } +}