diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d443b124c41..52d72c3c529 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1712,15 +1712,17 @@ impl Type { resolver: &Resolver, ty: Ty, ) -> Type { - let environment = - resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); + let environment = resolver + .generic_def() + .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); Type { krate, env: environment, ty } } fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { let resolver = lexical_env.resolver(db.upcast()); - let environment = - resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); + let environment = resolver + .generic_def() + .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); Type { krate, env: environment, ty } } @@ -2051,11 +2053,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(&Ty, AssocItem) -> Option, ) -> Option { - // There should be no inference vars in types passed here - // FIXME check that? - // FIXME replace Unknown by bound vars here - let canonical = - Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) }; + let canonical = hir_ty::replace_errors_with_variables(self.ty.clone()); let env = self.env.clone(); let krate = krate.id; @@ -2223,8 +2221,9 @@ impl Type { walk_type(db, self, &mut cb); } - pub fn could_unify_with(&self, other: &Type) -> bool { - could_unify(&self.ty, &other.ty) + pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { + let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone())); + could_unify(db, self.env.clone(), &tys) } } diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs index e25ef866d7b..893e727c2e1 100644 --- a/crates/hir_ty/src/builder.rs +++ b/crates/hir_ty/src/builder.rs @@ -6,15 +6,15 @@ use chalk_ir::{ cast::{Cast, CastTo, Caster}, fold::Fold, interner::HasInterner, - AdtId, BoundVar, DebruijnIndex, Safety, Scalar, + AdtId, BoundVar, DebruijnIndex, Scalar, }; use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; use smallvec::SmallVec; use crate::{ db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, - CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, - TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId, + CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, + TyKind, ValueTyDefId, }; /// This is a builder for `Ty` or anything that needs a `Substitution`. @@ -77,15 +77,7 @@ impl TyBuilder<()> { } pub fn fn_ptr(sig: CallableSig) -> Ty { - TyKind::Function(FnPointer { - num_binders: 0, - sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, - substitution: FnSubst(Substitution::from_iter( - &Interner, - sig.params_and_return.iter().cloned(), - )), - }) - .intern(&Interner) + TyKind::Function(sig.to_fn_ptr()).intern(&Interner) } pub fn builtin(builtin: BuiltinType) -> Ty { diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs index 8f054d06bf5..b108fd559c4 100644 --- a/crates/hir_ty/src/chalk_db.rs +++ b/crates/hir_ty/src/chalk_db.rs @@ -344,20 +344,20 @@ impl<'a> chalk_solve::RustIrDatabase for ChalkContext<'a> { } fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase { - self + &self.db } } -impl<'a> chalk_ir::UnificationDatabase for ChalkContext<'a> { +impl<'a> chalk_ir::UnificationDatabase for &'a dyn HirDatabase { fn fn_def_variance( &self, fn_def_id: chalk_ir::FnDefId, ) -> chalk_ir::Variances { - self.db.fn_def_variance(self.krate, fn_def_id) + HirDatabase::fn_def_variance(*self, fn_def_id) } fn adt_variance(&self, adt_id: chalk_ir::AdtId) -> chalk_ir::Variances { - self.db.adt_variance(self.krate, adt_id) + HirDatabase::adt_variance(*self, adt_id) } } @@ -651,11 +651,7 @@ pub(crate) fn fn_def_datum_query( Arc::new(datum) } -pub(crate) fn fn_def_variance_query( - db: &dyn HirDatabase, - _krate: CrateId, - fn_def_id: FnDefId, -) -> Variances { +pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances { let callable_def: CallableDefId = from_chalk(db, fn_def_id); let generic_params = generics(db.upcast(), callable_def.into()); Variances::from_iter( @@ -666,7 +662,6 @@ pub(crate) fn fn_def_variance_query( pub(crate) fn adt_variance_query( db: &dyn HirDatabase, - _krate: CrateId, chalk_ir::AdtId(adt_id): AdtId, ) -> Variances { let generic_params = generics(db.upcast(), adt_id.into()); diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs index 5232a7d8038..df340a6ca17 100644 --- a/crates/hir_ty/src/chalk_ext.rs +++ b/crates/hir_ty/src/chalk_ext.rs @@ -18,6 +18,7 @@ pub trait TyExt { fn is_unit(&self) -> bool; fn is_never(&self) -> bool; fn is_unknown(&self) -> bool; + fn is_ty_var(&self) -> bool; fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; fn as_builtin(&self) -> Option; @@ -55,6 +56,10 @@ impl TyExt for Ty { matches!(self.kind(&Interner), TyKind::Error) } + fn is_ty_var(&self) -> bool { + matches!(self.kind(&Interner), TyKind::InferenceVar(_, _)) + } + fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { match self.kind(&Interner) { TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 9da0a02e334..be5b9110ed9 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs @@ -117,10 +117,10 @@ pub trait HirDatabase: DefDatabase + Upcast { fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc; #[salsa::invoke(chalk_db::fn_def_variance_query)] - fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk_db::Variances; + fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances; #[salsa::invoke(chalk_db::adt_variance_query)] - fn adt_variance(&self, krate: CrateId, adt_id: chalk_db::AdtId) -> chalk_db::Variances; + fn adt_variance(&self, adt_id: chalk_db::AdtId) -> chalk_db::Variances; #[salsa::invoke(chalk_db::associated_ty_value_query)] fn associated_ty_value( @@ -134,14 +134,14 @@ pub trait HirDatabase: DefDatabase + Upcast { fn trait_solve( &self, krate: CrateId, - goal: crate::Canonical>, + goal: crate::Canonical>, ) -> Option; #[salsa::invoke(crate::traits::trait_solve_query)] fn trait_solve_query( &self, krate: CrateId, - goal: crate::Canonical>, + goal: crate::Canonical>, ) -> Option; #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] @@ -168,7 +168,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc fn trait_solve_wait( db: &dyn HirDatabase, krate: CrateId, - goal: crate::Canonical>, + goal: crate::Canonical>, ) -> Option { let _p = profile::span("trait_solve::wait"); db.trait_solve_query(krate, goal) diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 0ee851a74c7..f1cebbdb983 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs @@ -13,8 +13,6 @@ //! to certain types. To record this, we use the union-find implementation from //! the `ena` crate, which is extracted from rustc. -use std::borrow::Cow; -use std::mem; use std::ops::Index; use std::sync::Arc; @@ -27,8 +25,8 @@ use hir_def::{ path::{path, Path}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::TypeRef, - AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, - TypeAliasId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup, + TraitId, TypeAliasId, VariantId, }; use hir_expand::{diagnostics::DiagnosticSink, name::name}; use la_arena::ArenaMap; @@ -36,13 +34,11 @@ use rustc_hash::FxHashMap; use stdx::impl_from; use syntax::SmolStr; -use super::{ - DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty, -}; +use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; use crate::{ db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, - lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, - TyBuilder, TyExt, TyKind, + lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder, + TyExt, TyKind, }; // This lint has a false positive here. See the link below for details. @@ -106,6 +102,14 @@ impl Default for BindingMode { } } +#[derive(Debug)] +pub(crate) struct InferOk { + goals: Vec>, +} +#[derive(Debug)] +pub(crate) struct TypeError; +pub(crate) type InferResult = Result; + /// A mismatch between an expected and an inferred type. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeMismatch { @@ -217,10 +221,8 @@ struct InferenceContext<'a> { owner: DefWithBodyId, body: Arc, resolver: Resolver, - table: unify::InferenceTable, + table: unify::InferenceTable<'a>, trait_env: Arc, - obligations: Vec, - last_obligations_check: Option, result: InferenceResult, /// The return type of the function being inferred, or the closure if we're /// currently within one. @@ -252,15 +254,15 @@ fn find_breakable<'c>( impl<'a> InferenceContext<'a> { fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self { + let krate = owner.module(db.upcast()).krate(); + let trait_env = owner + .as_generic_def_id() + .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d)); InferenceContext { result: InferenceResult::default(), - table: unify::InferenceTable::new(), - obligations: Vec::default(), - last_obligations_check: None, + table: unify::InferenceTable::new(db, trait_env.clone()), + trait_env, return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature - trait_env: owner - .as_generic_def_id() - .map_or_else(Default::default, |d| db.trait_environment(d)), db, owner, body: db.body(owner), @@ -271,19 +273,25 @@ impl<'a> InferenceContext<'a> { } fn err_ty(&self) -> Ty { - TyKind::Error.intern(&Interner) + self.result.standard_types.unknown.clone() } fn resolve_all(mut self) -> InferenceResult { // FIXME resolve obligations as well (use Guidance if necessary) + self.table.resolve_obligations_as_possible(); + + // make sure diverging type variables are marked as such + self.table.propagate_diverging_flag(); let mut result = std::mem::take(&mut self.result); for ty in result.type_of_expr.values_mut() { - let resolved = self.table.resolve_ty_completely(ty.clone()); - *ty = resolved; + *ty = self.table.resolve_ty_completely(ty.clone()); } for ty in result.type_of_pat.values_mut() { - let resolved = self.table.resolve_ty_completely(ty.clone()); - *ty = resolved; + *ty = self.table.resolve_ty_completely(ty.clone()); + } + for mismatch in result.type_mismatches.values_mut() { + mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone()); + mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone()); } result } @@ -337,6 +345,14 @@ impl<'a> InferenceContext<'a> { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty.kind(&Interner) { TyKind::Error => self.table.new_type_var(), + TyKind::InferenceVar(..) => { + let ty_resolved = self.resolve_ty_shallow(&ty); + if ty_resolved.is_unknown() { + self.table.new_type_var() + } else { + ty + } + } _ => ty, } } @@ -346,66 +362,19 @@ impl<'a> InferenceContext<'a> { } fn resolve_obligations_as_possible(&mut self) { - if self.last_obligations_check == Some(self.table.revision) { - // no change - return; - } - let _span = profile::span("resolve_obligations_as_possible"); - - self.last_obligations_check = Some(self.table.revision); - let obligations = mem::replace(&mut self.obligations, Vec::new()); - for obligation in obligations { - let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone()); - let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); - let solution = - self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); - - match solution { - Some(Solution::Unique(canonical_subst)) => { - canonicalized.apply_solution( - self, - Canonical { - binders: canonical_subst.binders, - // FIXME: handle constraints - value: canonical_subst.value.subst, - }, - ); - } - Some(Solution::Ambig(Guidance::Definite(substs))) => { - canonicalized.apply_solution(self, substs); - self.obligations.push(obligation); - } - Some(_) => { - // FIXME use this when trying to resolve everything at the end - self.obligations.push(obligation); - } - None => { - // FIXME obligation cannot be fulfilled => diagnostic - } - }; - } + self.table.resolve_obligations_as_possible(); } fn push_obligation(&mut self, o: DomainGoal) { - self.obligations.push(o); - self.last_obligations_check = None; + self.table.register_obligation(o.cast(&Interner)); } fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { self.table.unify(ty1, ty2) } - /// Resolves the type as far as currently possible, replacing type variables - /// by their known types. All types returned by the infer_* functions should - /// be resolved as far as possible, i.e. contain no type variables with - /// known type. - fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { + fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { self.resolve_obligations_as_possible(); - - self.table.resolve_ty_as_possible(ty) - } - - fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { self.table.resolve_ty_shallow(ty) } @@ -439,7 +408,7 @@ impl<'a> InferenceContext<'a> { }; self.push_obligation(trait_ref.cast(&Interner)); self.push_obligation(alias_eq.cast(&Interner)); - self.resolve_ty_as_possible(ty) + ty } None => self.err_ty(), } @@ -452,25 +421,7 @@ impl<'a> InferenceContext<'a> { /// call). `make_ty` handles this already, but e.g. for field types we need /// to do it as well. fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { - let ty = self.resolve_ty_as_possible(ty); - fold_tys( - ty, - |ty, _| match ty.kind(&Interner) { - TyKind::Alias(AliasTy::Projection(proj_ty)) => { - self.normalize_projection_ty(proj_ty.clone()) - } - _ => ty, - }, - DebruijnIndex::INNERMOST, - ) - } - - fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { - let var = self.table.new_type_var(); - let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; - let obligation = alias_eq.cast(&Interner); - self.push_obligation(obligation); - var + self.table.normalize_associated_types_in(ty) } fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option) { @@ -720,17 +671,23 @@ impl<'a> InferenceContext<'a> { /// When inferring an expression, we propagate downward whatever type hint we /// are able in the form of an `Expectation`. #[derive(Clone, PartialEq, Eq, Debug)] -struct Expectation { - ty: Ty, - /// See the `rvalue_hint` method. - rvalue_hint: bool, +enum Expectation { + None, + HasType(Ty), + // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts + RValueLikeUnsized(Ty), } impl Expectation { /// The expectation that the type of the expression needs to equal the given /// type. fn has_type(ty: Ty) -> Self { - Expectation { ty, rvalue_hint: false } + if ty.is_unknown() { + // FIXME: get rid of this? + Expectation::None + } else { + Expectation::HasType(ty) + } } /// The following explanation is copied straight from rustc: @@ -754,24 +711,41 @@ impl Expectation { /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. fn rvalue_hint(ty: Ty) -> Self { - Expectation { ty, rvalue_hint: true } + match ty.strip_references().kind(&Interner) { + TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty), + _ => Expectation::has_type(ty), + } } /// This expresses no expectation on the type. fn none() -> Self { - Expectation { - // FIXME - ty: TyKind::Error.intern(&Interner), - rvalue_hint: false, + Expectation::None + } + + fn resolve(&self, table: &mut unify::InferenceTable) -> Expectation { + match self { + Expectation::None => Expectation::None, + Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)), + Expectation::RValueLikeUnsized(t) => { + Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t)) + } } } - fn coercion_target(&self) -> Ty { - if self.rvalue_hint { - // FIXME - TyKind::Error.intern(&Interner) - } else { - self.ty.clone() + fn to_option(&self, table: &mut unify::InferenceTable) -> Option { + match self.resolve(table) { + Expectation::None => None, + Expectation::HasType(t) | + // Expectation::Castable(t) | + Expectation::RValueLikeUnsized(t) => Some(t), + } + } + + fn only_has_type(&self, table: &mut unify::InferenceTable) -> Option { + match self { + Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)), + // Expectation::Castable(_) | + Expectation::RValueLikeUnsized(_) | Expectation::None => None, } } } diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 1f463a42556..765a02b1ced 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs @@ -2,156 +2,414 @@ //! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions //! like going from `&Vec` to `&[T]`. //! -//! See: https://doc.rust-lang.org/nomicon/coercions.html +//! See https://doc.rust-lang.org/nomicon/coercions.html and +//! librustc_typeck/check/coercion.rs. use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; -use hir_def::lang_item::LangItemTarget; +use hir_def::{expr::ExprId, lang_item::LangItemTarget}; -use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; +use crate::{ + autoderef, infer::TypeMismatch, static_lifetime, Canonical, DomainGoal, FnPointer, FnSig, + Interner, Solution, Substitution, Ty, TyBuilder, TyExt, TyKind, +}; -use super::{InEnvironment, InferenceContext}; +use super::{InEnvironment, InferOk, InferResult, InferenceContext, TypeError}; impl<'a> InferenceContext<'a> { /// Unify two types, but may coerce the first one to the second one /// using "implicit coercion rules" if needed. pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { - let from_ty = self.resolve_ty_shallow(from_ty).into_owned(); + let from_ty = self.resolve_ty_shallow(from_ty); let to_ty = self.resolve_ty_shallow(to_ty); - self.coerce_inner(from_ty, &to_ty) + match self.coerce_inner(from_ty, &to_ty) { + Ok(result) => { + self.table.register_infer_ok(result); + true + } + Err(_) => { + // FIXME deal with error + false + } + } } /// Merge two types from different branches, with possible coercion. /// /// Mostly this means trying to coerce one to the other, but - /// - if we have two function types for different functions, we need to + /// - if we have two function types for different functions or closures, we need to /// coerce both to function pointers; /// - if we were concerned with lifetime subtyping, we'd need to look for a /// least upper bound. - pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { - if self.coerce(ty1, ty2) { - ty2.clone() - } else if self.coerce(ty2, ty1) { - ty1.clone() - } else { - if let (TyKind::FnDef(..), TyKind::FnDef(..)) = - (ty1.kind(&Interner), ty2.kind(&Interner)) - { + pub(super) fn coerce_merge_branch(&mut self, id: Option, ty1: &Ty, ty2: &Ty) -> Ty { + let ty1 = self.resolve_ty_shallow(ty1); + let ty2 = self.resolve_ty_shallow(ty2); + // Special case: two function types. Try to coerce both to + // pointers to have a chance at getting a match. See + // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 + let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) { + (TyKind::FnDef(..), TyKind::FnDef(..)) + | (TyKind::Closure(..), TyKind::FnDef(..)) + | (TyKind::FnDef(..), TyKind::Closure(..)) + | (TyKind::Closure(..), TyKind::Closure(..)) => { + // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, + // we should be coercing the closure to a fn pointer of the safety of the FnDef cov_mark::hit!(coerce_fn_reification); - // Special case: two function types. Try to coerce both to - // pointers to have a chance at getting a match. See - // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 - let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); - let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); - let ptr_ty1 = TyBuilder::fn_ptr(sig1); - let ptr_ty2 = TyBuilder::fn_ptr(sig2); - self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) - } else { - cov_mark::hit!(coerce_merge_fail_fallback); - ty1.clone() + let sig = ty1.callable_sig(self.db).expect("FnDef without callable sig"); + Some(sig) + } + _ => None, + }; + if let Some(sig) = sig { + let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(&Interner); + let result1 = self.coerce_inner(ty1.clone(), &target_ty); + let result2 = self.coerce_inner(ty2.clone(), &target_ty); + if let (Ok(result1), Ok(result2)) = (result1, result2) { + self.table.register_infer_ok(result1); + self.table.register_infer_ok(result2); + return target_ty; + } + } + + // It might not seem like it, but order is important here: ty1 is our + // "previous" type, ty2 is the "new" one being added. If the previous + // type is a type variable and the new one is `!`, trying it the other + // way around first would mean we make the type variable `!`, instead of + // just marking it as possibly diverging. + if self.coerce(&ty2, &ty1) { + ty1.clone() + } else if self.coerce(&ty1, &ty2) { + ty2.clone() + } else { + if let Some(id) = id { + self.result + .type_mismatches + .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2.clone() }); + } + cov_mark::hit!(coerce_merge_fail_fallback); + ty1.clone() + } + } + + fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult { + if from_ty.is_never() { + // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound + // type variable, we want `?T` to fallback to `!` if not + // otherwise constrained. An example where this arises: + // + // let _: Option = Some({ return; }); + // + // here, we would coerce from `!` to `?T`. + match to_ty.kind(&Interner) { + TyKind::InferenceVar(tv, TyVariableKind::General) => { + self.table.set_diverging(*tv, true); + } + _ => {} + } + return Ok(InferOk { goals: Vec::new() }); + } + + // Consider coercing the subtype to a DST + if let Ok(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { + return Ok(ret); + } + + // Examine the supertype and consider auto-borrowing. + match to_ty.kind(&Interner) { + TyKind::Raw(mt, _) => { + return self.coerce_ptr(from_ty, to_ty, *mt); + } + TyKind::Ref(mt, _, _) => { + return self.coerce_ref(from_ty, to_ty, *mt); + } + _ => {} + } + + match from_ty.kind(&Interner) { + TyKind::FnDef(..) => { + // Function items are coercible to any closure + // type; function pointers are not (that would + // require double indirection). + // Additionally, we permit coercion of function + // items to drop the unsafe qualifier. + self.coerce_from_fn_item(from_ty, to_ty) + } + TyKind::Function(from_fn_ptr) => { + // We permit coercion of fn pointers to drop the + // unsafe qualifier. + self.coerce_from_fn_pointer(from_ty.clone(), from_fn_ptr, to_ty) + } + TyKind::Closure(_, from_substs) => { + // Non-capturing closures are coercible to + // function pointers or unsafe function pointers. + // It cannot convert closures that require unsafe. + self.coerce_closure_to_fn(from_ty.clone(), from_substs, to_ty) + } + _ => { + // Otherwise, just use unification rules. + self.table.try_unify(&from_ty, to_ty) } } } - fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { - match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { - // Never type will make type variable to fallback to Never Type instead of Unknown. - (TyKind::Never, TyKind::InferenceVar(tv, TyVariableKind::General)) => { - self.table.type_variable_table.set_diverging(*tv, true); - return true; - } - (TyKind::Never, _) => return true, + fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> InferResult { + let (_is_ref, from_mt, from_inner) = match from_ty.kind(&Interner) { + TyKind::Ref(mt, _, ty) => (true, mt, ty), + TyKind::Raw(mt, ty) => (false, mt, ty), + _ => return self.table.try_unify(&from_ty, to_ty), + }; - // Trivial cases, this should go after `never` check to - // avoid infer result type to be never - _ => { - if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) { - return true; - } - } - } + coerce_mutabilities(*from_mt, to_mt)?; - // Pointer weakening and function to pointer - match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { - // `*mut T` -> `*const T` - (TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => { - from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner); - } - // `&mut T` -> `&T` - (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => { - from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner); - } - // `&T` -> `*const T` - // `&mut T` -> `*mut T`/`*const T` - (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..)) - | (TyKind::Ref(Mutability::Mut, _, substs), &TyKind::Raw(m2, ..)) => { - from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner); - } + // Check that the types which they point at are compatible. + let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(&Interner); + // FIXME: behavior differs based on is_ref once we're computing adjustments + self.table.try_unify(&from_raw, to_ty) + } - // Illegal mutability conversion - (TyKind::Raw(Mutability::Not, ..), TyKind::Raw(Mutability::Mut, ..)) - | (TyKind::Ref(Mutability::Not, ..), TyKind::Ref(Mutability::Mut, ..)) => return false, + /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. + /// To match `A` with `B`, autoderef will be performed, + /// calling `deref`/`deref_mut` where necessary. + fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> InferResult { + match from_ty.kind(&Interner) { + TyKind::Ref(mt, _, _) => { + coerce_mutabilities(*mt, to_mt)?; + } + _ => return self.table.try_unify(&from_ty, to_ty), + }; - // `{function_type}` -> `fn()` - (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) { - None => return false, - Some(sig) => { - from_ty = TyBuilder::fn_ptr(sig); - } + // NOTE: this code is mostly copied and adapted from rustc, and + // currently more complicated than necessary, carrying errors around + // etc.. This complication will become necessary when we actually track + // details of coercion errors though, so I think it's useful to leave + // the structure like it is. + + let canonicalized = self.canonicalize(from_ty.clone()); + let autoderef = autoderef::autoderef( + self.db, + self.resolver.krate(), + InEnvironment { + goal: canonicalized.value.clone(), + environment: self.trait_env.env.clone(), }, + ); + let mut first_error = None; + let mut found = None; - (TyKind::Closure(.., substs), TyKind::Function { .. }) => { - from_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone(); + for (autoderefs, referent_ty) in autoderef.enumerate() { + if autoderefs == 0 { + // Don't let this pass, otherwise it would cause + // &T to autoref to &&T. + continue; } - _ => {} - } + let referent_ty = canonicalized.decanonicalize_ty(referent_ty.value); - if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { - return ret; - } - - // Auto Deref if cannot coerce - match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { - // FIXME: DerefMut - (TyKind::Ref(.., st1), TyKind::Ref(.., st2)) => { - self.unify_autoderef_behind_ref(st1, st2) + // At this point, we have deref'd `a` to `referent_ty`. So + // imagine we are coercing from `&'a mut Vec` to `&'b mut [T]`. + // In the autoderef loop for `&'a mut Vec`, we would get + // three callbacks: + // + // - `&'a mut Vec` -- 0 derefs, just ignore it + // - `Vec` -- 1 deref + // - `[T]` -- 2 deref + // + // At each point after the first callback, we want to + // check to see whether this would match out target type + // (`&'b mut [T]`) if we autoref'd it. We can't just + // compare the referent types, though, because we still + // have to consider the mutability. E.g., in the case + // we've been considering, we have an `&mut` reference, so + // the `T` in `[T]` needs to be unified with equality. + // + // Therefore, we construct reference types reflecting what + // the types will be after we do the final auto-ref and + // compare those. Note that this means we use the target + // mutability [1], since it may be that we are coercing + // from `&mut T` to `&U`. + let lt = static_lifetime(); // FIXME: handle lifetimes correctly, see rustc + let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(&Interner); + match self.table.try_unify(&derefd_from_ty, to_ty) { + Ok(result) => { + found = Some(result); + break; + } + Err(err) => { + if first_error.is_none() { + first_error = Some(err); + } + } } + } - // Otherwise, normal unify - _ => self.unify(&from_ty, to_ty), + // Extract type or return an error. We return the first error + // we got, which should be from relating the "base" type + // (e.g., in example above, the failure from relating `Vec` + // to the target type), since that should be the least + // confusing. + let result = match found { + Some(d) => d, + None => { + let err = first_error.expect("coerce_borrowed_pointer had no error"); + return Err(err); + } + }; + + Ok(result) + } + + /// Attempts to coerce from the type of a Rust function item into a function pointer. + fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult { + match to_ty.kind(&Interner) { + TyKind::Function(_) => { + let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig"); + + // FIXME check ABI: Intrinsics are not coercible to function pointers + // FIXME Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396) + + // FIXME rustc normalizes assoc types in the sig here, not sure if necessary + + let from_sig = from_sig.to_fn_ptr(); + let from_fn_pointer = TyKind::Function(from_sig.clone()).intern(&Interner); + let ok = self.coerce_from_safe_fn(from_fn_pointer, &from_sig, to_ty)?; + + Ok(ok) + } + _ => self.table.try_unify(&from_ty, to_ty), + } + } + + fn coerce_from_fn_pointer( + &mut self, + from_ty: Ty, + from_f: &FnPointer, + to_ty: &Ty, + ) -> InferResult { + self.coerce_from_safe_fn(from_ty, from_f, to_ty) + } + + fn coerce_from_safe_fn( + &mut self, + from_ty: Ty, + from_fn_ptr: &FnPointer, + to_ty: &Ty, + ) -> InferResult { + if let TyKind::Function(to_fn_ptr) = to_ty.kind(&Interner) { + if let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) = + (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety) + { + let from_unsafe = + TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(&Interner); + return self.table.try_unify(&from_unsafe, to_ty); + } + } + self.table.try_unify(&from_ty, to_ty) + } + + /// Attempts to coerce from the type of a non-capturing closure into a + /// function pointer. + fn coerce_closure_to_fn( + &mut self, + from_ty: Ty, + from_substs: &Substitution, + to_ty: &Ty, + ) -> InferResult { + match to_ty.kind(&Interner) { + TyKind::Function(fn_ty) /* if from_substs is non-capturing (FIXME) */ => { + // We coerce the closure, which has fn type + // `extern "rust-call" fn((arg0,arg1,...)) -> _` + // to + // `fn(arg0,arg1,...) -> _` + // or + // `unsafe fn(arg0,arg1,...) -> _` + let safety = fn_ty.sig.safety; + let pointer_ty = coerce_closure_fn_ty(from_substs, safety); + self.table.try_unify(&pointer_ty, to_ty) + } + _ => self.table.try_unify(&from_ty, to_ty), } } /// Coerce a type using `from_ty: CoerceUnsized` /// /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html - fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option { + fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> InferResult { + // These 'if' statements require some explanation. + // The `CoerceUnsized` trait is special - it is only + // possible to write `impl CoerceUnsized for A` where + // A and B have 'matching' fields. This rules out the following + // two types of blanket impls: + // + // `impl CoerceUnsized for SomeType` + // `impl CoerceUnsized for T` + // + // Both of these trigger a special `CoerceUnsized`-related error (E0376) + // + // We can take advantage of this fact to avoid performing unecessary work. + // If either `source` or `target` is a type variable, then any applicable impl + // would need to be generic over the self-type (`impl CoerceUnsized for T`) + // or generic over the `CoerceUnsized` type parameter (`impl CoerceUnsized for + // SomeType`). + // + // However, these are exactly the kinds of impls which are forbidden by + // the compiler! Therefore, we can be sure that coercion will always fail + // when either the source or target type is a type variable. This allows us + // to skip performing any trait selection, and immediately bail out. + if from_ty.is_ty_var() { + return Err(TypeError); + } + if to_ty.is_ty_var() { + return Err(TypeError); + } + + // Handle reborrows before trying to solve `Source: CoerceUnsized`. + let coerce_from = match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { + (TyKind::Ref(from_mt, _, from_inner), TyKind::Ref(to_mt, _, _)) => { + coerce_mutabilities(*from_mt, *to_mt)?; + + let lt = static_lifetime(); + TyKind::Ref(*to_mt, lt, from_inner.clone()).intern(&Interner) + } + (TyKind::Ref(from_mt, _, from_inner), TyKind::Raw(to_mt, _)) => { + coerce_mutabilities(*from_mt, *to_mt)?; + + TyKind::Raw(*to_mt, from_inner.clone()).intern(&Interner) + } + _ => from_ty.clone(), + }; + let krate = self.resolver.krate().unwrap(); let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { Some(LangItemTarget::TraitId(trait_)) => trait_, - _ => return None, + _ => return Err(TypeError), }; let trait_ref = { let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait); if b.remaining() != 2 { // The CoerceUnsized trait should have two generic params: Self and T. - return None; + return Err(TypeError); } - b.push(from_ty.clone()).push(to_ty.clone()).build() + b.push(coerce_from.clone()).push(to_ty.clone()).build() }; - let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner)); + let goal: InEnvironment = + InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner)); - let canonicalizer = self.canonicalizer(); - let canonicalized = canonicalizer.canonicalize_obligation(goal); + let canonicalized = self.canonicalize(goal); - let solution = self.db.trait_solve(krate, canonicalized.value.clone())?; + // FIXME: rustc's coerce_unsized is more specialized -- it only tries to + // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the + // rest for later. Also, there's some logic about sized type variables. + // Need to find out in what cases this is necessary + let solution = self + .db + .trait_solve(krate, canonicalized.value.clone().cast(&Interner)) + .ok_or(TypeError)?; match solution { Solution::Unique(v) => { canonicalized.apply_solution( - self, + &mut self.table, Canonical { binders: v.binders, // FIXME handle constraints @@ -159,38 +417,40 @@ impl<'a> InferenceContext<'a> { }, ); } - _ => return None, + // FIXME: should we accept ambiguous results here? + _ => return Err(TypeError), }; - Some(true) - } - - /// Unify `from_ty` to `to_ty` with optional auto Deref - /// - /// Note that the parameters are already stripped the outer reference. - fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { - let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); - let to_ty = self.resolve_ty_shallow(&to_ty); - // FIXME: Auto DerefMut - for derefed_ty in autoderef::autoderef( - self.db, - self.resolver.krate(), - InEnvironment { - goal: canonicalized.value.clone(), - environment: self.trait_env.env.clone(), - }, - ) { - let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); - let from_ty = self.resolve_ty_shallow(&derefed_ty); - // Stop when constructor matches. - if from_ty.equals_ctor(&to_ty) { - // It will not recurse to `coerce`. - return self.table.unify(&from_ty, &to_ty); - } else if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) { - return true; - } - } - - false + Ok(InferOk { goals: Vec::new() }) + } +} + +fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty { + let closure_sig = closure_substs.at(&Interner, 0).assert_ty_ref(&Interner).clone(); + match closure_sig.kind(&Interner) { + TyKind::Function(fn_ty) => TyKind::Function(FnPointer { + num_binders: fn_ty.num_binders, + sig: FnSig { safety, ..fn_ty.sig }, + substitution: fn_ty.substitution.clone(), + }) + .intern(&Interner), + _ => TyKind::Error.intern(&Interner), + } +} + +fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer { + FnPointer { + num_binders: fn_ty.num_binders, + sig: FnSig { safety: chalk_ir::Safety::Unsafe, ..fn_ty.sig }, + substitution: fn_ty.substitution, + } +} + +fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> { + match (from, to) { + (Mutability::Mut, Mutability::Mut) + | (Mutability::Mut, Mutability::Not) + | (Mutability::Not, Mutability::Not) => Ok(()), + (Mutability::Not, Mutability::Mut) => Err(TypeError), } } diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 7278faeec08..08c05c67cc9 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -35,39 +35,43 @@ use super::{ impl<'a> InferenceContext<'a> { pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(tgt_expr, expected); - if ty.is_never() { + if self.resolve_ty_shallow(&ty).is_never() { // Any expression that produces a value of type `!` must have diverged self.diverges = Diverges::Always; } - let could_unify = self.unify(&ty, &expected.ty); - if !could_unify { - self.result.type_mismatches.insert( - tgt_expr.into(), - TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, - ); + if let Some(expected_ty) = expected.only_has_type(&mut self.table) { + let could_unify = self.unify(&ty, &expected_ty); + if !could_unify { + self.result.type_mismatches.insert( + tgt_expr.into(), + TypeMismatch { expected: expected_ty.clone(), actual: ty.clone() }, + ); + } } - self.resolve_ty_as_possible(ty) + ty } /// Infer type of expression with possibly implicit coerce to the expected type. /// Return the type after possible coercion. pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(expr, &expected); - let ty = if !self.coerce(&ty, &expected.coercion_target()) { - self.result.type_mismatches.insert( - expr.into(), - TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, - ); - // Return actual type when type mismatch. - // This is needed for diagnostic when return type mismatch. - ty - } else if expected.coercion_target().is_unknown() { - ty + let ty = if let Some(target) = expected.only_has_type(&mut self.table) { + if !self.coerce(&ty, &target) { + self.result.type_mismatches.insert( + expr.into(), + TypeMismatch { expected: target.clone(), actual: ty.clone() }, + ); + // Return actual type when type mismatch. + // This is needed for diagnostic when return type mismatch. + ty + } else { + target.clone() + } } else { - expected.ty.clone() + ty }; - self.resolve_ty_as_possible(ty) + ty } fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec, Ty)> { @@ -98,10 +102,10 @@ impl<'a> InferenceContext<'a> { goal: projection.trait_ref(self.db).cast(&Interner), environment: trait_env, }; - let canonical = self.canonicalizer().canonicalize_obligation(obligation.clone()); - if self.db.trait_solve(krate, canonical.value).is_some() { + let canonical = self.canonicalize(obligation.clone()); + if self.db.trait_solve(krate, canonical.value.cast(&Interner)).is_some() { self.push_obligation(obligation.goal); - let return_ty = self.normalize_projection_ty(projection); + let return_ty = self.table.normalize_projection_ty(projection); Some((arg_tys, return_ty)) } else { None @@ -131,17 +135,21 @@ impl<'a> InferenceContext<'a> { let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let mut both_arms_diverge = Diverges::Always; + let mut result_ty = self.table.new_type_var(); let then_ty = self.infer_expr_inner(*then_branch, &expected); both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); + result_ty = self.coerce_merge_branch(Some(*then_branch), &result_ty, &then_ty); let else_ty = match else_branch { Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), None => TyBuilder::unit(), }; both_arms_diverge &= self.diverges; + // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None? + result_ty = self.coerce_merge_branch(*else_branch, &result_ty, &else_ty); self.diverges = condition_diverges | both_arms_diverge; - self.coerce_merge_branch(&then_ty, &else_ty) + result_ty } Expr::Block { statements, tail, label, id: _ } => { let old_resolver = mem::replace( @@ -277,12 +285,13 @@ impl<'a> InferenceContext<'a> { // Eagerly try to relate the closure type with the expected // type, otherwise we often won't have enough information to // infer the body. - self.coerce(&closure_ty, &expected.ty); + if let Some(t) = expected.only_has_type(&mut self.table) { + self.coerce(&closure_ty, &t); + } // Now go through the argument patterns for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { - let resolved = self.resolve_ty_as_possible(arg_ty); - self.infer_pat(*arg_pat, &resolved, BindingMode::default()); + self.infer_pat(*arg_pat, &arg_ty, BindingMode::default()); } let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); @@ -297,13 +306,13 @@ impl<'a> InferenceContext<'a> { } Expr::Call { callee, args } => { let callee_ty = self.infer_expr(*callee, &Expectation::none()); - let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); + let canonicalized = self.canonicalize(callee_ty.clone()); let mut derefs = autoderef( self.db, self.resolver.krate(), InEnvironment { goal: canonicalized.value.clone(), - environment: self.trait_env.env.clone(), + environment: self.table.trait_env.env.clone(), }, ); let (param_tys, ret_ty): (Vec, Ty) = derefs @@ -350,7 +359,7 @@ impl<'a> InferenceContext<'a> { let arm_ty = self.infer_expr_inner(arm.expr, &expected); all_arms_diverge &= self.diverges; - result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); + result_ty = self.coerce_merge_branch(Some(arm.expr), &result_ty, &arm_ty); } self.diverges = matchee_diverges | all_arms_diverge; @@ -364,12 +373,6 @@ impl<'a> InferenceContext<'a> { } Expr::Continue { .. } => TyKind::Never.intern(&Interner), Expr::Break { expr, label } => { - let val_ty = if let Some(expr) = expr { - self.infer_expr(*expr, &Expectation::none()) - } else { - TyBuilder::unit() - }; - let last_ty = if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { ctxt.break_ty.clone() @@ -377,7 +380,14 @@ impl<'a> InferenceContext<'a> { self.err_ty() }; - let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); + let val_ty = if let Some(expr) = expr { + self.infer_expr(*expr, &Expectation::none()) + } else { + TyBuilder::unit() + }; + + // FIXME: create a synthetic `()` during lowering so we have something to refer to here? + let merged_type = self.coerce_merge_branch(*expr, &last_ty, &val_ty); if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { ctxt.break_ty = merged_type; @@ -411,7 +421,9 @@ impl<'a> InferenceContext<'a> { self.write_variant_resolution(tgt_expr.into(), variant); } - self.unify(&ty, &expected.ty); + if let Some(t) = expected.only_has_type(&mut self.table) { + self.unify(&ty, &t); + } let substs = ty .as_adt() @@ -442,7 +454,7 @@ impl<'a> InferenceContext<'a> { } Expr::Field { expr, name } => { let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); - let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); + let canonicalized = self.canonicalize(receiver_ty); let ty = autoderef::autoderef( self.db, self.resolver.krate(), @@ -514,6 +526,7 @@ impl<'a> InferenceContext<'a> { self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) } Expr::Cast { expr, type_ref } => { + // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary) let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); let cast_ty = self.make_ty(type_ref); // FIXME check the cast... @@ -521,15 +534,17 @@ impl<'a> InferenceContext<'a> { } Expr::Ref { expr, rawness, mutability } => { let mutability = lower_to_chalk_mutability(*mutability); - let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = - &expected.ty.as_reference_or_ptr() + let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected + .only_has_type(&mut self.table) + .as_ref() + .and_then(|t| t.as_reference_or_ptr()) { - if *exp_mutability == Mutability::Mut && mutability == Mutability::Not { - // FIXME: throw type error - expected mut reference but found shared ref, + if exp_mutability == Mutability::Mut && mutability == Mutability::Not { + // FIXME: record type error - expected mut reference but found shared ref, // which cannot be coerced } - if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { - // FIXME: throw type error - expected reference but found ptr, + if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { + // FIXME: record type error - expected reference but found ptr, // which cannot be coerced } Expectation::rvalue_hint(Ty::clone(exp_inner)) @@ -556,10 +571,11 @@ impl<'a> InferenceContext<'a> { } Expr::UnaryOp { expr, op } => { let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); + let inner_ty = self.resolve_ty_shallow(&inner_ty); match op { UnaryOp::Deref => match self.resolver.krate() { Some(krate) => { - let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); + let canonicalized = self.canonicalize(inner_ty); match autoderef::deref( self.db, krate, @@ -612,8 +628,10 @@ impl<'a> InferenceContext<'a> { _ => Expectation::none(), }; let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); + let lhs_ty = self.resolve_ty_shallow(&lhs_ty); let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone()); let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); + let rhs_ty = self.resolve_ty_shallow(&rhs_ty); let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); @@ -676,7 +694,7 @@ impl<'a> InferenceContext<'a> { if let (Some(index_trait), Some(krate)) = (self.resolve_ops_index(), self.resolver.krate()) { - let canonicalized = self.canonicalizer().canonicalize_ty(base_ty); + let canonicalized = self.canonicalize(base_ty); let self_ty = method_resolution::resolve_indexing_op( self.db, &canonicalized.value, @@ -696,8 +714,12 @@ impl<'a> InferenceContext<'a> { } } Expr::Tuple { exprs } => { - let mut tys = match expected.ty.kind(&Interner) { - TyKind::Tuple(_, substs) => substs + let mut tys = match expected + .only_has_type(&mut self.table) + .as_ref() + .map(|t| t.kind(&Interner)) + { + Some(TyKind::Tuple(_, substs)) => substs .iter(&Interner) .map(|a| a.assert_ty_ref(&Interner).clone()) .chain(repeat_with(|| self.table.new_type_var())) @@ -713,14 +735,16 @@ impl<'a> InferenceContext<'a> { TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner) } Expr::Array(array) => { - let elem_ty = match expected.ty.kind(&Interner) { - TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), - _ => self.table.new_type_var(), - }; + let elem_ty = + match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) { + Some(TyKind::Array(st, _)) | Some(TyKind::Slice(st)) => st.clone(), + _ => self.table.new_type_var(), + }; let len = match array { Array::ElementList(items) => { for expr in items.iter() { + // FIXME: use CoerceMany (coerce_merge_branch) self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); } Some(items.len() as u64) @@ -785,7 +809,6 @@ impl<'a> InferenceContext<'a> { }; // use a new type variable if we got unknown here let ty = self.insert_type_vars_shallow(ty); - let ty = self.resolve_ty_as_possible(ty); self.write_expr_ty(tgt_expr, ty.clone()); ty } @@ -813,7 +836,6 @@ impl<'a> InferenceContext<'a> { } } - let ty = self.resolve_ty_as_possible(ty); self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr { expr, .. } => { @@ -836,7 +858,9 @@ impl<'a> InferenceContext<'a> { // we don't even make an attempt at coercion self.table.new_maybe_never_var() } else { - self.coerce(&TyBuilder::unit(), &expected.coercion_target()); + if let Some(t) = expected.only_has_type(&mut self.table) { + self.coerce(&TyBuilder::unit(), &t); + } TyBuilder::unit() } }; @@ -852,7 +876,7 @@ impl<'a> InferenceContext<'a> { generic_args: Option<&GenericArgs>, ) -> Ty { let receiver_ty = self.infer_expr(receiver, &Expectation::none()); - let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); + let canonicalized_receiver = self.canonicalize(receiver_ty.clone()); let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); @@ -891,7 +915,8 @@ impl<'a> InferenceContext<'a> { }; // Apply autoref so the below unification works correctly // FIXME: return correct autorefs from lookup_method - let actual_receiver_ty = match expected_receiver_ty.as_reference() { + let actual_receiver_ty = match self.resolve_ty_shallow(&expected_receiver_ty).as_reference() + { Some((_, lifetime, mutability)) => { TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner) } @@ -971,6 +996,7 @@ impl<'a> InferenceContext<'a> { } fn register_obligations_for_call(&mut self, callable_ty: &Ty) { + let callable_ty = self.resolve_ty_shallow(&callable_ty); if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) { let def: CallableDefId = from_chalk(self.db, *fn_def); let generic_predicates = self.db.generic_predicates(def.into()); diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index b15f4977dd9..9c8e3b6aea9 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -94,14 +94,15 @@ impl<'a> InferenceContext<'a> { pub(super) fn infer_pat( &mut self, pat: PatId, - mut expected: &Ty, + expected: &Ty, mut default_bm: BindingMode, ) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem + let mut expected = self.resolve_ty_shallow(expected); if is_non_ref_pat(&body, pat) { while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - expected = inner; + expected = self.resolve_ty_shallow(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), @@ -147,9 +148,9 @@ impl<'a> InferenceContext<'a> { } Pat::Or(ref pats) => { if let Some((first_pat, rest)) = pats.split_first() { - let ty = self.infer_pat(*first_pat, expected, default_bm); + let ty = self.infer_pat(*first_pat, &expected, default_bm); for pat in rest { - self.infer_pat(*pat, expected, default_bm); + self.infer_pat(*pat, &expected, default_bm); } ty } else { @@ -173,13 +174,13 @@ impl<'a> InferenceContext<'a> { Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( p.as_deref(), subpats, - expected, + &expected, default_bm, pat, *ellipsis, ), Pat::Record { path: p, args: fields, ellipsis: _ } => { - self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat) + self.infer_record_pat(p.as_deref(), fields, &expected, default_bm, pat) } Pat::Path(path) => { // FIXME use correct resolver for the surrounding expression @@ -193,7 +194,7 @@ impl<'a> InferenceContext<'a> { BindingMode::convert(*mode) }; let inner_ty = if let Some(subpat) = subpat { - self.infer_pat(*subpat, expected, default_bm) + self.infer_pat(*subpat, &expected, default_bm) } else { expected.clone() }; @@ -206,7 +207,6 @@ impl<'a> InferenceContext<'a> { } BindingMode::Move => inner_ty.clone(), }; - let bound_ty = self.resolve_ty_as_possible(bound_ty); self.write_pat_ty(pat, bound_ty); return inner_ty; } @@ -265,13 +265,12 @@ impl<'a> InferenceContext<'a> { }; // use a new type variable if we got error type here let ty = self.insert_type_vars_shallow(ty); - if !self.unify(&ty, expected) { + if !self.unify(&ty, &expected) { self.result.type_mismatches.insert( pat.into(), TypeMismatch { expected: expected.clone(), actual: ty.clone() }, ); } - let ty = self.resolve_ty_as_possible(ty); self.write_pat_ty(pat, ty.clone()); ty } diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 495282eba85..14c99eafd31 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs @@ -65,7 +65,6 @@ impl<'a> InferenceContext<'a> { let typable: ValueTyDefId = match value { ValueNs::LocalBinding(pat) => { let ty = self.result.type_of_pat.get(pat)?.clone(); - let ty = self.resolve_ty_as_possible(ty); return Some(ty); } ValueNs::FunctionId(it) => it.into(), @@ -218,14 +217,14 @@ impl<'a> InferenceContext<'a> { return Some(result); } - let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); + let canonical_ty = self.canonicalize(ty.clone()); let krate = self.resolver.krate()?; let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); method_resolution::iterate_method_candidates( &canonical_ty.value, self.db, - self.trait_env.clone(), + self.table.trait_env.clone(), krate, &traits_in_scope, None, @@ -275,6 +274,7 @@ impl<'a> InferenceContext<'a> { name: &Name, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { + let ty = self.resolve_ty_shallow(ty); let (enum_id, subst) = match ty.as_adt() { Some((AdtId::EnumId(e), subst)) => (e, subst), _ => return None, diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index d8e0b432064..21d3fb54e9d 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs @@ -1,177 +1,95 @@ //! Unification and canonicalization logic. -use std::borrow::Cow; +use std::{fmt, mem, sync::Arc}; use chalk_ir::{ - cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex, - VariableKind, + cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, TyVariableKind, + UniverseIndex, }; -use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; +use chalk_solve::infer::ParameterEnaVariableExt; +use ena::unify::UnifyKey; -use super::{DomainGoal, InferenceContext}; +use super::{InferOk, InferResult, InferenceContext, TypeError}; use crate::{ - fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, - DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution, - Ty, TyExt, TyKind, WhereClause, + db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, + DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, ProjectionTy, + Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind, }; impl<'a> InferenceContext<'a> { - pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b> + pub(super) fn canonicalize + HasInterner>( + &mut self, + t: T, + ) -> Canonicalized where - 'a: 'b, + T::Result: HasInterner, { - Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() } + // try to resolve obligations before canonicalizing, since this might + // result in new knowledge about variables + self.resolve_obligations_as_possible(); + self.table.canonicalize(t) } } -pub(super) struct Canonicalizer<'a, 'b> -where - 'a: 'b, -{ - ctx: &'b mut InferenceContext<'a>, - free_vars: Vec<(InferenceVar, TyVariableKind)>, - /// A stack of type variables that is used to detect recursive types (which - /// are an error, but we need to protect against them to avoid stack - /// overflows). - var_stack: Vec, -} - -#[derive(Debug)] +#[derive(Debug, Clone)] pub(super) struct Canonicalized where T: HasInterner, { pub(super) value: Canonical, - free_vars: Vec<(InferenceVar, TyVariableKind)>, -} - -impl<'a, 'b> Canonicalizer<'a, 'b> { - fn add(&mut self, free_var: InferenceVar, kind: TyVariableKind) -> usize { - self.free_vars.iter().position(|&(v, _)| v == free_var).unwrap_or_else(|| { - let next_index = self.free_vars.len(); - self.free_vars.push((free_var, kind)); - next_index - }) - } - - fn do_canonicalize + HasInterner>( - &mut self, - t: T, - binders: DebruijnIndex, - ) -> T { - fold_tys( - t, - |ty, binders| match ty.kind(&Interner) { - &TyKind::InferenceVar(var, kind) => { - let inner = from_inference_var(var); - if self.var_stack.contains(&inner) { - // recursive type - return self.ctx.table.type_variable_table.fallback_value(var, kind); - } - if let Some(known_ty) = - self.ctx.table.var_unification_table.inlined_probe_value(inner).known() - { - self.var_stack.push(inner); - let result = self.do_canonicalize(known_ty.clone(), binders); - self.var_stack.pop(); - result - } else { - let root = self.ctx.table.var_unification_table.find(inner); - let position = self.add(to_inference_var(root), kind); - TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner) - } - } - _ => ty, - }, - binders, - ) - } - - fn into_canonicalized>( - self, - result: T, - ) -> Canonicalized { - let kinds = self - .free_vars - .iter() - .map(|&(_, k)| chalk_ir::WithKind::new(VariableKind::Ty(k), UniverseIndex::ROOT)); - Canonicalized { - value: Canonical { - value: result, - binders: CanonicalVarKinds::from_iter(&Interner, kinds), - }, - free_vars: self.free_vars, - } - } - - pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized { - let result = self.do_canonicalize(ty, DebruijnIndex::INNERMOST); - self.into_canonicalized(result) - } - - pub(crate) fn canonicalize_obligation( - mut self, - obligation: InEnvironment, - ) -> Canonicalized> { - let result = match obligation.goal { - DomainGoal::Holds(wc) => { - DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) - } - _ => unimplemented!(), - }; - self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment }) - } + free_vars: Vec, } impl> Canonicalized { pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty { - crate::fold_free_vars(ty, |bound, _binders| { - let (v, k) = self.free_vars[bound.index]; - TyKind::InferenceVar(v, k).intern(&Interner) - }) + chalk_ir::Substitute::apply(&self.free_vars, ty, &Interner) } pub(super) fn apply_solution( &self, - ctx: &mut InferenceContext<'_>, + ctx: &mut InferenceTable, solution: Canonical, ) { // the solution may contain new variables, which we need to convert to new inference vars let new_vars = Substitution::from_iter( &Interner, solution.binders.iter(&Interner).map(|k| match k.kind { - VariableKind::Ty(TyVariableKind::General) => { - ctx.table.new_type_var().cast(&Interner) - } - VariableKind::Ty(TyVariableKind::Integer) => { - ctx.table.new_integer_var().cast(&Interner) - } - VariableKind::Ty(TyVariableKind::Float) => { - ctx.table.new_float_var().cast(&Interner) - } + VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(&Interner), + VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(&Interner), + VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(&Interner), // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere VariableKind::Lifetime => static_lifetime().cast(&Interner), _ => panic!("const variable in solution"), }), ); - for (i, ty) in solution.value.iter(&Interner).enumerate() { - let (v, k) = self.free_vars[i]; - // eagerly replace projections in the type; we may be getting types - // e.g. from where clauses where this hasn't happened yet - let ty = ctx.normalize_associated_types_in( - new_vars.apply(ty.assert_ty_ref(&Interner).clone(), &Interner), - ); - ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty); + for (i, v) in solution.value.iter(&Interner).enumerate() { + let var = self.free_vars[i].clone(); + if let Some(ty) = v.ty(&Interner) { + // eagerly replace projections in the type; we may be getting types + // e.g. from where clauses where this hasn't happened yet + let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), &Interner)); + ctx.unify(var.assert_ty_ref(&Interner), &ty); + } else { + let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), &Interner)); + } } } } -pub fn could_unify(t1: &Ty, t2: &Ty) -> bool { - InferenceTable::new().unify(t1, t2) +pub fn could_unify( + db: &dyn HirDatabase, + env: Arc, + tys: &Canonical<(Ty, Ty)>, +) -> bool { + unify(db, env, tys).is_some() } -pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option { - let mut table = InferenceTable::new(); +pub(crate) fn unify( + db: &dyn HirDatabase, + env: Arc, + tys: &Canonical<(Ty, Ty)>, +) -> Option { + let mut table = InferenceTable::new(db, env); let vars = Substitution::from_iter( &Interner, tys.binders @@ -187,77 +105,151 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option { } // default any type vars that weren't unified back to their original bound vars // (kind of hacky) - for (i, var) in vars.iter(&Interner).enumerate() { - let var = var.assert_ty_ref(&Interner); - if &*table.resolve_ty_shallow(var) == var { - table.unify( - var, - &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i)).intern(&Interner), - ); - } - } + let find_var = |iv| { + vars.iter(&Interner).position(|v| match v.interned() { + chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner), + chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner), + chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner), + } == Some(iv)) + }; + let fallback = |iv, kind, default, binder| match kind { + chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv) + .map_or(default, |i| BoundVar::new(binder, i).to_ty(&Interner).cast(&Interner)), + chalk_ir::VariableKind::Lifetime => find_var(iv) + .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(&Interner).cast(&Interner)), + chalk_ir::VariableKind::Const(ty) => find_var(iv) + .map_or(default, |i| BoundVar::new(binder, i).to_const(&Interner, ty).cast(&Interner)), + }; Some(Substitution::from_iter( &Interner, vars.iter(&Interner) - .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())), + .map(|v| table.resolve_with_fallback(v.assert_ty_ref(&Interner).clone(), fallback)), )) } -#[derive(Clone, Debug)] -pub(super) struct TypeVariableTable { - inner: Vec, -} - -impl TypeVariableTable { - fn push(&mut self, data: TypeVariableData) { - self.inner.push(data); - } - - pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { - self.inner[from_inference_var(iv).0 as usize].diverging = diverging; - } - - fn is_diverging(&mut self, iv: InferenceVar) -> bool { - self.inner[from_inference_var(iv).0 as usize].diverging - } - - fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { - match kind { - _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never, - TyVariableKind::General => TyKind::Error, - TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), - TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), - } - .intern(&Interner) - } -} - #[derive(Copy, Clone, Debug)] pub(crate) struct TypeVariableData { diverging: bool, } -#[derive(Clone, Debug)] -pub(crate) struct InferenceTable { - pub(super) var_unification_table: InPlaceUnificationTable, - pub(super) type_variable_table: TypeVariableTable, - pub(super) revision: u32, +type ChalkInferenceTable = chalk_solve::infer::InferenceTable; + +#[derive(Clone)] +pub(crate) struct InferenceTable<'a> { + pub(crate) db: &'a dyn HirDatabase, + pub(crate) trait_env: Arc, + var_unification_table: ChalkInferenceTable, + type_variable_table: Vec, + pending_obligations: Vec>>, } -impl InferenceTable { - pub(crate) fn new() -> Self { +impl<'a> InferenceTable<'a> { + pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc) -> Self { InferenceTable { - var_unification_table: InPlaceUnificationTable::new(), - type_variable_table: TypeVariableTable { inner: Vec::new() }, - revision: 0, + db, + trait_env, + var_unification_table: ChalkInferenceTable::new(), + type_variable_table: Vec::new(), + pending_obligations: Vec::new(), } } + /// Chalk doesn't know about the `diverging` flag, so when it unifies two + /// type variables of which one is diverging, the chosen root might not be + /// diverging and we have no way of marking it as such at that time. This + /// function goes through all type variables and make sure their root is + /// marked as diverging if necessary, so that resolving them gives the right + /// result. + pub(super) fn propagate_diverging_flag(&mut self) { + for i in 0..self.type_variable_table.len() { + if !self.type_variable_table[i].diverging { + continue; + } + let v = InferenceVar::from(i as u32); + let root = self.var_unification_table.inference_var_root(v); + if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) { + data.diverging = true; + } + } + } + + pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { + self.type_variable_table[iv.index() as usize].diverging = diverging; + } + + fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { + match kind { + _ if self + .type_variable_table + .get(iv.index() as usize) + .map_or(false, |data| data.diverging) => + { + TyKind::Never + } + TyVariableKind::General => TyKind::Error, + TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), + TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), + } + .intern(&Interner) + } + + pub(super) fn canonicalize + HasInterner>( + &mut self, + t: T, + ) -> Canonicalized + where + T::Result: HasInterner, + { + let result = self.var_unification_table.canonicalize(&Interner, t); + let free_vars = result + .free_vars + .into_iter() + .map(|free_var| free_var.to_generic_arg(&Interner)) + .collect(); + Canonicalized { value: result.quantified, free_vars } + } + + /// Recurses through the given type, normalizing associated types mentioned + /// in it by replacing them by type variables and registering obligations to + /// resolve later. This should be done once for every type we get from some + /// type annotation (e.g. from a let type annotation, field type or function + /// call). `make_ty` handles this already, but e.g. for field types we need + /// to do it as well. + pub(super) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { + fold_tys( + ty, + |ty, _| match ty.kind(&Interner) { + TyKind::Alias(AliasTy::Projection(proj_ty)) => { + self.normalize_projection_ty(proj_ty.clone()) + } + _ => ty, + }, + DebruijnIndex::INNERMOST, + ) + } + + pub(super) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { + let var = self.new_type_var(); + let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; + let obligation = alias_eq.cast(&Interner); + self.register_obligation(obligation); + var + } + + fn extend_type_variable_table(&mut self, to_index: usize) { + self.type_variable_table.extend( + (0..1 + to_index - self.type_variable_table.len()) + .map(|_| TypeVariableData { diverging: false }), + ); + } + fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { - self.type_variable_table.push(TypeVariableData { diverging }); - let key = self.var_unification_table.new_key(TypeVarValue::Unknown); - assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); - TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner) + let var = self.var_unification_table.new_variable(UniverseIndex::ROOT); + // Chalk might have created some type variables for its own purposes that we don't know about... + self.extend_type_variable_table(var.index() as usize); + assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); + self.type_variable_table[var.index() as usize].diverging = diverging; + var.to_ty_with_kind(&Interner, kind) } pub(crate) fn new_type_var(&mut self) -> Ty { @@ -276,350 +268,261 @@ impl InferenceTable { self.new_var(TyVariableKind::General, true) } - pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { - self.resolve_ty_completely_inner(&mut Vec::new(), ty) - } - - pub(crate) fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { - self.resolve_ty_as_possible_inner(&mut Vec::new(), ty) - } - - pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { - self.unify_inner(ty1, ty2, 0) - } - - pub(crate) fn unify_substs( + pub(crate) fn resolve_with_fallback( &mut self, - substs1: &Substitution, - substs2: &Substitution, - depth: usize, - ) -> bool { - substs1.iter(&Interner).zip(substs2.iter(&Interner)).all(|(t1, t2)| { - self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth) - }) + t: T, + fallback: impl Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + ) -> T::Result + where + T: HasInterner + Fold, + { + self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback) } - fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { - if depth > 1000 { - // prevent stackoverflows - panic!("infinite recursion in unification"); - } - if ty1 == ty2 { - return true; - } - // try to resolve type vars first - let ty1 = self.resolve_ty_shallow(ty1); - let ty2 = self.resolve_ty_shallow(ty2); - if ty1.equals_ctor(&ty2) { - match (ty1.kind(&Interner), ty2.kind(&Interner)) { - (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2)) - | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2)) - | ( - TyKind::Function(FnPointer { substitution: FnSubst(substs1), .. }), - TyKind::Function(FnPointer { substitution: FnSubst(substs2), .. }), - ) - | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2)) - | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2)) - | (TyKind::AssociatedType(_, substs1), TyKind::AssociatedType(_, substs2)) - | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => { - self.unify_substs(substs1, substs2, depth + 1) - } - (TyKind::Array(ty1, c1), TyKind::Array(ty2, c2)) if c1 == c2 => { - self.unify_inner(ty1, ty2, depth + 1) - } - (TyKind::Ref(_, _, ty1), TyKind::Ref(_, _, ty2)) - | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2)) - | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), - _ => true, /* we checked equals_ctor already */ - } - } else if let (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) = - (ty1.kind(&Interner), ty2.kind(&Interner)) - { - self.unify_substs(substs1, substs2, depth + 1) + fn resolve_with_fallback_inner( + &mut self, + var_stack: &mut Vec, + t: T, + fallback: &impl Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, + ) -> T::Result + where + T: HasInterner + Fold, + { + t.fold_with( + &mut resolve::Resolver { table: self, var_stack, fallback }, + DebruijnIndex::INNERMOST, + ) + .expect("fold failed unexpectedly") + } + + pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { + self.resolve_with_fallback(ty, |_, _, d, _| d) + } + + /// Unify two types and register new trait goals that arise from that. + pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { + let result = if let Ok(r) = self.try_unify(ty1, ty2) { + r } else { - self.unify_inner_trivial(&ty1, &ty2, depth) - } + return false; + }; + self.register_infer_ok(result); + true } - pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { - match (ty1.kind(&Interner), ty2.kind(&Interner)) { - (TyKind::Error, _) | (_, TyKind::Error) => true, - - (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, - - (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2)) - if dyn1.bounds.skip_binders().interned().len() - == dyn2.bounds.skip_binders().interned().len() => - { - for (pred1, pred2) in dyn1 - .bounds - .skip_binders() - .interned() - .iter() - .zip(dyn2.bounds.skip_binders().interned().iter()) - { - if !self.unify_preds(pred1.skip_binders(), pred2.skip_binders(), depth + 1) { - return false; - } - } - true - } - - ( - TyKind::InferenceVar(tv1, TyVariableKind::General), - TyKind::InferenceVar(tv2, TyVariableKind::General), - ) - | ( - TyKind::InferenceVar(tv1, TyVariableKind::Integer), - TyKind::InferenceVar(tv2, TyVariableKind::Integer), - ) - | ( - TyKind::InferenceVar(tv1, TyVariableKind::Float), - TyKind::InferenceVar(tv2, TyVariableKind::Float), - ) if self.type_variable_table.is_diverging(*tv1) - == self.type_variable_table.is_diverging(*tv2) => - { - // both type vars are unknown since we tried to resolve them - if !self - .var_unification_table - .unioned(from_inference_var(*tv1), from_inference_var(*tv2)) - { - self.var_unification_table - .union(from_inference_var(*tv1), from_inference_var(*tv2)); - self.revision += 1; - } - true - } - - // The order of MaybeNeverTypeVar matters here. - // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. - // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. - (TyKind::InferenceVar(tv, TyVariableKind::General), other) - | (other, TyKind::InferenceVar(tv, TyVariableKind::General)) - | ( - TyKind::InferenceVar(tv, TyVariableKind::Integer), - other @ TyKind::Scalar(Scalar::Int(_)), - ) - | ( - other @ TyKind::Scalar(Scalar::Int(_)), - TyKind::InferenceVar(tv, TyVariableKind::Integer), - ) - | ( - TyKind::InferenceVar(tv, TyVariableKind::Integer), - other @ TyKind::Scalar(Scalar::Uint(_)), - ) - | ( - other @ TyKind::Scalar(Scalar::Uint(_)), - TyKind::InferenceVar(tv, TyVariableKind::Integer), - ) - | ( - TyKind::InferenceVar(tv, TyVariableKind::Float), - other @ TyKind::Scalar(Scalar::Float(_)), - ) - | ( - other @ TyKind::Scalar(Scalar::Float(_)), - TyKind::InferenceVar(tv, TyVariableKind::Float), - ) => { - // the type var is unknown since we tried to resolve it - self.var_unification_table.union_value( - from_inference_var(*tv), - TypeVarValue::Known(other.clone().intern(&Interner)), - ); - self.revision += 1; - true - } - - _ => false, - } - } - - fn unify_preds(&mut self, pred1: &WhereClause, pred2: &WhereClause, depth: usize) -> bool { - match (pred1, pred2) { - (WhereClause::Implemented(tr1), WhereClause::Implemented(tr2)) - if tr1.trait_id == tr2.trait_id => - { - self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1) - } - ( - WhereClause::AliasEq(AliasEq { alias: alias1, ty: ty1 }), - WhereClause::AliasEq(AliasEq { alias: alias2, ty: ty2 }), - ) => { - let (substitution1, substitution2) = match (alias1, alias2) { - (AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2)) - if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id => - { - (&projection_ty1.substitution, &projection_ty2.substitution) - } - (AliasTy::Opaque(opaque1), AliasTy::Opaque(opaque2)) - if opaque1.opaque_ty_id == opaque2.opaque_ty_id => - { - (&opaque1.substitution, &opaque2.substitution) - } - _ => return false, - }; - self.unify_substs(&substitution1, &substitution2, depth + 1) - && self.unify_inner(&ty1, &ty2, depth + 1) - } - _ => false, + /// Unify two types and return new trait goals arising from it, so the + /// caller needs to deal with them. + pub(crate) fn try_unify>(&mut self, t1: &T, t2: &T) -> InferResult { + match self.var_unification_table.relate( + &Interner, + &self.db, + &self.trait_env.env, + chalk_ir::Variance::Invariant, + t1, + t2, + ) { + Ok(result) => Ok(InferOk { goals: result.goals }), + Err(chalk_ir::NoSolution) => Err(TypeError), } } /// If `ty` is a type variable with known type, returns that type; /// otherwise, return ty. - pub(crate) fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { - let mut ty = Cow::Borrowed(ty); - // The type variable could resolve to a int/float variable. Hence try - // resolving up to three times; each type of variable shouldn't occur - // more than once - for i in 0..3 { - if i > 0 { - cov_mark::hit!(type_var_resolves_to_int_var); - } - match ty.kind(&Interner) { - TyKind::InferenceVar(tv, _) => { - let inner = from_inference_var(*tv); - match self.var_unification_table.inlined_probe_value(inner).known() { - Some(known_ty) => { - // The known_ty can't be a type var itself - ty = Cow::Owned(known_ty.clone()); - } - _ => return ty, - } + pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty { + self.var_unification_table.normalize_ty_shallow(&Interner, ty).unwrap_or_else(|| ty.clone()) + } + + pub(crate) fn register_obligation(&mut self, goal: Goal) { + let in_env = InEnvironment::new(&self.trait_env.env, goal); + self.register_obligation_in_env(in_env) + } + + fn register_obligation_in_env(&mut self, goal: InEnvironment) { + let canonicalized = self.canonicalize(goal); + if !self.try_resolve_obligation(&canonicalized) { + self.pending_obligations.push(canonicalized); + } + } + + pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk) { + infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal)); + } + + pub(crate) fn resolve_obligations_as_possible(&mut self) { + let _span = profile::span("resolve_obligations_as_possible"); + let mut changed = true; + let mut obligations = Vec::new(); + while changed { + changed = false; + mem::swap(&mut self.pending_obligations, &mut obligations); + for canonicalized in obligations.drain(..) { + if !self.check_changed(&canonicalized) { + self.pending_obligations.push(canonicalized); + continue; } - _ => return ty, + changed = true; + let uncanonical = chalk_ir::Substitute::apply( + &canonicalized.free_vars, + canonicalized.value.value, + &Interner, + ); + self.register_obligation_in_env(uncanonical); } } - log::error!("Inference variable still not resolved: {:?}", ty); - ty } - /// Resolves the type as far as currently possible, replacing type variables - /// by their known types. All types returned by the infer_* functions should - /// be resolved as far as possible, i.e. contain no type variables with - /// known type. - fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { - fold_tys( - ty, - |ty, _| match ty.kind(&Interner) { - &TyKind::InferenceVar(tv, kind) => { - let inner = from_inference_var(tv); - if tv_stack.contains(&inner) { - cov_mark::hit!(type_var_cycles_resolve_as_possible); - // recursive type - return self.type_variable_table.fallback_value(tv, kind); - } - if let Some(known_ty) = - self.var_unification_table.inlined_probe_value(inner).known() - { - // known_ty may contain other variables that are known by now - tv_stack.push(inner); - let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); - tv_stack.pop(); - result - } else { - ty - } - } - _ => ty, - }, - DebruijnIndex::INNERMOST, - ) + /// This checks whether any of the free variables in the `canonicalized` + /// have changed (either been unified with another variable, or with a + /// value). If this is not the case, we don't need to try to solve the goal + /// again -- it'll give the same result as last time. + fn check_changed(&mut self, canonicalized: &Canonicalized>) -> bool { + canonicalized.free_vars.iter().any(|var| { + let iv = match var.data(&Interner) { + chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner), + chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner), + chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner), + } + .expect("free var is not inference var"); + if self.var_unification_table.probe_var(iv).is_some() { + return true; + } + let root = self.var_unification_table.inference_var_root(iv); + iv != root + }) } - /// Resolves the type completely; type variables without known type are - /// replaced by TyKind::Unknown. - fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec, ty: Ty) -> Ty { - fold_tys( - ty, - |ty, _| match ty.kind(&Interner) { - &TyKind::InferenceVar(tv, kind) => { - let inner = from_inference_var(tv); - if tv_stack.contains(&inner) { - cov_mark::hit!(type_var_cycles_resolve_completely); - // recursive type - return self.type_variable_table.fallback_value(tv, kind); - } - if let Some(known_ty) = - self.var_unification_table.inlined_probe_value(inner).known() - { - // known_ty may contain other variables that are known by now - tv_stack.push(inner); - let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); - tv_stack.pop(); - result - } else { - self.type_variable_table.fallback_value(tv, kind) - } - } - _ => ty, - }, - DebruijnIndex::INNERMOST, - ) - } -} + fn try_resolve_obligation( + &mut self, + canonicalized: &Canonicalized>, + ) -> bool { + let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone()); -/// The ID of a type variable. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(super) struct TypeVarId(pub(super) u32); - -impl UnifyKey for TypeVarId { - type Value = TypeVarValue; - - fn index(&self) -> u32 { - self.0 - } - - fn from_index(i: u32) -> Self { - TypeVarId(i) - } - - fn tag() -> &'static str { - "TypeVarId" - } -} - -fn from_inference_var(var: InferenceVar) -> TypeVarId { - TypeVarId(var.index()) -} - -fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar { - index.into() -} - -/// The value of a type variable: either we already know the type, or we don't -/// know it yet. -#[derive(Clone, PartialEq, Eq, Debug)] -pub(super) enum TypeVarValue { - Known(Ty), - Unknown, -} - -impl TypeVarValue { - fn known(&self) -> Option<&Ty> { - match self { - TypeVarValue::Known(ty) => Some(ty), - TypeVarValue::Unknown => None, + match solution { + Some(Solution::Unique(canonical_subst)) => { + canonicalized.apply_solution( + self, + Canonical { + binders: canonical_subst.binders, + // FIXME: handle constraints + value: canonical_subst.value.subst, + }, + ); + true + } + Some(Solution::Ambig(Guidance::Definite(substs))) => { + canonicalized.apply_solution(self, substs); + false + } + Some(_) => { + // FIXME use this when trying to resolve everything at the end + false + } + None => { + // FIXME obligation cannot be fulfilled => diagnostic + true + } } } } -impl UnifyValue for TypeVarValue { - type Error = NoError; +impl<'a> fmt::Debug for InferenceTable<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish() + } +} - fn unify_values(value1: &Self, value2: &Self) -> Result { - match (value1, value2) { - // We should never equate two type variables, both of which have - // known types. Instead, we recursively equate those types. - (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!( - "equating two type variables, both of which have known types: {:?} and {:?}", - t1, t2 - ), +mod resolve { + use super::InferenceTable; + use crate::{ + ConcreteConst, Const, ConstData, ConstValue, DebruijnIndex, GenericArg, InferenceVar, + Interner, Ty, TyVariableKind, VariableKind, + }; + use chalk_ir::{ + cast::Cast, + fold::{Fold, Folder}, + Fallible, + }; + use hir_def::type_ref::ConstScalar; - // If one side is known, prefer that one. - (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), - (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), + pub(super) struct Resolver<'a, 'b, F> { + pub(super) table: &'a mut InferenceTable<'b>, + pub(super) var_stack: &'a mut Vec, + pub(super) fallback: F, + } + impl<'a, 'b, 'i, F> Folder<'i, Interner> for Resolver<'a, 'b, F> + where + F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i, + { + fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { + self + } - (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), + fn interner(&self) -> &'i Interner { + &Interner + } + + fn fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + outer_binder: DebruijnIndex, + ) -> Fallible { + let var = self.table.var_unification_table.inference_var_root(var); + if self.var_stack.contains(&var) { + // recursive type + let default = self.table.fallback_value(var, kind).cast(&Interner); + return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(&Interner) + .clone()); + } + let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { + // known_ty may contain other variables that are known by now + self.var_stack.push(var); + let result = + known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly"); + self.var_stack.pop(); + result.assert_ty_ref(&Interner).clone() + } else { + let default = self.table.fallback_value(var, kind).cast(&Interner); + (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder) + .assert_ty_ref(&Interner) + .clone() + }; + Ok(result) + } + + fn fold_inference_const( + &mut self, + ty: Ty, + var: InferenceVar, + outer_binder: DebruijnIndex, + ) -> Fallible { + let var = self.table.var_unification_table.inference_var_root(var); + let default = ConstData { + ty: ty.clone(), + value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }), + } + .intern(&Interner) + .cast(&Interner); + if self.var_stack.contains(&var) { + // recursive + return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder) + .assert_const_ref(&Interner) + .clone()); + } + let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) { + // known_ty may contain other variables that are known by now + self.var_stack.push(var); + let result = + known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly"); + self.var_stack.pop(); + result.assert_const_ref(&Interner).clone() + } else { + (self.fallback)(var, VariableKind::Const(ty), default, outer_binder) + .assert_const_ref(&Interner) + .clone() + }; + Ok(result) } } } diff --git a/crates/hir_ty/src/interner.rs b/crates/hir_ty/src/interner.rs index 7b41197477a..29ffdd9b7f3 100644 --- a/crates/hir_ty/src/interner.rs +++ b/crates/hir_ty/src/interner.rs @@ -15,9 +15,15 @@ use std::{fmt, sync::Arc}; #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct Interner; -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(PartialEq, Eq, Hash)] pub struct InternedWrapper(T); +impl fmt::Debug for InternedWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + impl std::ops::Deref for InternedWrapper { type Target = T; @@ -101,66 +107,65 @@ impl chalk_ir::interner::Interner for Interner { opaque_ty: &chalk_ir::OpaqueTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) + Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) } fn debug_opaque_ty_id( opaque_ty_id: chalk_ir::OpaqueTyId, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) + Some(fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()) } fn debug_ty(ty: &chalk_ir::Ty, fmt: &mut fmt::Formatter<'_>) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) + Some(write!(fmt, "{:?}", ty.data(&Interner))) } fn debug_lifetime( lifetime: &chalk_ir::Lifetime, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) + Some(write!(fmt, "{:?}", lifetime.data(&Interner))) } fn debug_generic_arg( parameter: &GenericArg, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) + Some(write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())) } fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) + let goal_data = goal.data(&Interner); + Some(write!(fmt, "{:?}", goal_data)) } fn debug_goals( goals: &chalk_ir::Goals, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) + Some(write!(fmt, "{:?}", goals.debug(&Interner))) } fn debug_program_clause_implication( pci: &chalk_ir::ProgramClauseImplication, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) + Some(write!(fmt, "{:?}", pci.debug(&Interner))) } fn debug_substitution( substitution: &chalk_ir::Substitution, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) + Some(write!(fmt, "{:?}", substitution.debug(&Interner))) } fn debug_separator_trait_ref( separator_trait_ref: &chalk_ir::SeparatorTraitRef, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| { - Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) - }) + Some(write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))) } fn debug_fn_def_id( @@ -173,47 +178,43 @@ impl chalk_ir::interner::Interner for Interner { constant: &chalk_ir::Const, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) + Some(write!(fmt, "{:?}", constant.data(&Interner))) } fn debug_variable_kinds( variable_kinds: &chalk_ir::VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) + Some(write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))) } fn debug_variable_kinds_with_angles( variable_kinds: &chalk_ir::VariableKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| { - Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt)) - }) + Some(write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))) } fn debug_canonical_var_kinds( canonical_var_kinds: &chalk_ir::CanonicalVarKinds, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| { - Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt)) - }) + Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))) } fn debug_program_clause( clause: &chalk_ir::ProgramClause, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) + Some(write!(fmt, "{:?}", clause.data(&Interner))) } fn debug_program_clauses( clauses: &chalk_ir::ProgramClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) + Some(write!(fmt, "{:?}", clauses.as_slice(&Interner))) } fn debug_quantified_where_clauses( clauses: &chalk_ir::QuantifiedWhereClauses, fmt: &mut fmt::Formatter<'_>, ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) + Some(write!(fmt, "{:?}", clauses.as_slice(&Interner))) } fn intern_ty(&self, kind: chalk_ir::TyKind) -> Self::InternedType { diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 15b61bedc18..72093d75a2e 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs @@ -43,8 +43,9 @@ use hir_def::{ type_ref::{ConstScalar, Rawness}, TypeParamId, }; +use stdx::always; -use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; +use crate::{db::HirDatabase, utils::generics}; pub use autoderef::autoderef; pub use builder::TyBuilder; @@ -113,6 +114,7 @@ pub type FnSig = chalk_ir::FnSig; pub type InEnvironment = chalk_ir::InEnvironment; pub type DomainGoal = chalk_ir::DomainGoal; +pub type Goal = chalk_ir::Goal; pub type AliasEq = chalk_ir::AliasEq; pub type Solution = chalk_solve::Solution; pub type ConstrainedSubst = chalk_ir::ConstrainedSubst; @@ -167,6 +169,7 @@ pub fn make_canonical>( Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) } } +// FIXME: get rid of this, just replace it by FnPointer /// A function signature as seen by type inference: Several parameter types and /// one return type. #[derive(Clone, PartialEq, Eq, Debug)] @@ -203,6 +206,17 @@ impl CallableSig { } } + pub fn to_fn_ptr(&self) -> FnPointer { + FnPointer { + num_binders: 0, + sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs }, + substitution: FnSubst(Substitution::from_iter( + &Interner, + self.params_and_return.iter().cloned(), + )), + } + } + pub fn params(&self) -> &[Ty] { &self.params_and_return[0..self.params_and_return.len() - 1] } @@ -314,3 +328,58 @@ pub(crate) fn fold_tys + Fold>( } t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") } + +pub fn replace_errors_with_variables(t: T) -> Canonical +where + T: HasInterner + Fold, + T::Result: HasInterner, +{ + use chalk_ir::{ + fold::{Folder, SuperFold}, + Fallible, + }; + struct ErrorReplacer { + vars: usize, + } + impl<'i> Folder<'i, Interner> for ErrorReplacer { + fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> { + self + } + + fn interner(&self) -> &'i Interner { + &Interner + } + + fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible { + if let TyKind::Error = ty.kind(&Interner) { + let index = self.vars; + self.vars += 1; + Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(&Interner)) + } else { + let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; + Ok(ty) + } + } + + fn fold_inference_ty( + &mut self, + var: InferenceVar, + kind: TyVariableKind, + _outer_binder: DebruijnIndex, + ) -> Fallible { + always!(false); + Ok(TyKind::InferenceVar(var, kind).intern(&Interner)) + } + } + let mut error_replacer = ErrorReplacer { vars: 0 }; + let value = t + .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) + .expect("fold failed unexpectedly"); + let kinds = (0..error_replacer.vars).map(|_| { + chalk_ir::CanonicalVarKind::new( + chalk_ir::VariableKind::Ty(TyVariableKind::General), + chalk_ir::UniverseIndex::ROOT, + ) + }); + Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) } +} diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index bd8bb602864..8a375b97348 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -1035,9 +1035,11 @@ pub(crate) fn trait_environment_query( clauses.push(program_clause.into_from_env_clause(&Interner)); } + let krate = def.module(db.upcast()).krate(); + let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses); - Arc::new(TraitEnvironment { traits_from_clauses: traits_in_scope, env }) + Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env }) } /// Resolve the where clause(s) of an item with generics. diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 48bbcfd9ffa..08e385a42c8 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs @@ -577,6 +577,7 @@ fn iterate_method_candidates_by_receiver( if iterate_inherent_methods( self_ty, db, + env.clone(), name, Some(receiver_ty), krate, @@ -613,8 +614,16 @@ fn iterate_method_candidates_for_self_ty( name: Option<&Name>, mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, ) -> bool { - if iterate_inherent_methods(self_ty, db, name, None, krate, visible_from_module, &mut callback) - { + if iterate_inherent_methods( + self_ty, + db, + env.clone(), + name, + None, + krate, + visible_from_module, + &mut callback, + ) { return true; } iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) @@ -653,12 +662,12 @@ fn iterate_trait_method_candidates( for (_name, item) in data.items.iter() { // Don't pass a `visible_from_module` down to `is_valid_candidate`, // since only inherent methods should be included into visibility checking. - if !is_valid_candidate(db, name, receiver_ty, *item, self_ty, None) { + if !is_valid_candidate(db, env.clone(), name, receiver_ty, *item, self_ty, None) { continue; } if !known_implemented { let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); - if db.trait_solve(krate, goal).is_none() { + if db.trait_solve(krate, goal.cast(&Interner)).is_none() { continue 'traits; } } @@ -675,6 +684,7 @@ fn iterate_trait_method_candidates( fn iterate_inherent_methods( self_ty: &Canonical, db: &dyn HirDatabase, + env: Arc, name: Option<&Name>, receiver_ty: Option<&Canonical>, krate: CrateId, @@ -690,14 +700,24 @@ fn iterate_inherent_methods( for &impl_def in impls.for_self_ty(&self_ty.value) { for &item in db.impl_data(impl_def).items.iter() { - if !is_valid_candidate(db, name, receiver_ty, item, self_ty, visible_from_module) { + if !is_valid_candidate( + db, + env.clone(), + name, + receiver_ty, + item, + self_ty, + visible_from_module, + ) { continue; } // we have to check whether the self type unifies with the type // that the impl is for. If we have a receiver type, this // already happens in `is_valid_candidate` above; if not, we // check it here - if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { + if receiver_ty.is_none() + && inherent_impl_substs(db, env.clone(), impl_def, self_ty).is_none() + { cov_mark::hit!(impl_self_type_match_without_receiver); continue; } @@ -722,7 +742,7 @@ pub fn resolve_indexing_op( let deref_chain = autoderef_method_receiver(db, krate, ty); for ty in deref_chain { let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); - if db.trait_solve(krate, goal).is_some() { + if db.trait_solve(krate, goal.cast(&Interner)).is_some() { return Some(ty); } } @@ -731,6 +751,7 @@ pub fn resolve_indexing_op( fn is_valid_candidate( db: &dyn HirDatabase, + env: Arc, name: Option<&Name>, receiver_ty: Option<&Canonical>, item: AssocItemId, @@ -749,7 +770,7 @@ fn is_valid_candidate( if !data.has_self_param() { return false; } - let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { + let transformed_receiver_ty = match transform_receiver_ty(db, env, m, self_ty) { Some(ty) => ty, None => return false, }; @@ -776,6 +797,7 @@ fn is_valid_candidate( pub(crate) fn inherent_impl_substs( db: &dyn HirDatabase, + env: Arc, impl_id: ImplId, self_ty: &Canonical, ) -> Option { @@ -798,7 +820,7 @@ pub(crate) fn inherent_impl_substs( binders: CanonicalVarKinds::from_iter(&Interner, kinds), value: (self_ty_with_vars, self_ty.value.clone()), }; - let substs = super::infer::unify(&tys)?; + let substs = super::infer::unify(db, env, &tys)?; // We only want the substs for the vars we added, not the ones from self_ty. // Also, if any of the vars we added are still in there, we replace them by // Unknown. I think this can only really happen if self_ty contained @@ -823,6 +845,7 @@ fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution fn transform_receiver_ty( db: &dyn HirDatabase, + env: Arc, function_id: FunctionId, self_ty: &Canonical, ) -> Option { @@ -832,7 +855,7 @@ fn transform_receiver_ty( .fill_with_unknown() .build(), AssocContainerId::ImplId(impl_id) => { - let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; + let impl_substs = inherent_impl_substs(db, env, impl_id, &self_ty)?; TyBuilder::subst_for_def(db, function_id) .use_parent_substs(&impl_substs) .fill_with_unknown() @@ -852,7 +875,7 @@ pub fn implements_trait( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env, trait_, ty.clone()); - let solution = db.trait_solve(krate, goal); + let solution = db.trait_solve(krate, goal.cast(&Interner)); solution.is_some() } @@ -865,7 +888,7 @@ pub fn implements_trait_unique( trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env, trait_, ty.clone()); - let solution = db.trait_solve(krate, goal); + let solution = db.trait_solve(krate, goal.cast(&Interner)); matches!(solution, Some(crate::Solution::Unique(_))) } diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 19047106912..bb568ea372e 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs @@ -1,6 +1,6 @@ use expect_test::expect; -use super::{check_infer, check_infer_with_mismatches}; +use super::{check_infer, check_infer_with_mismatches, check_types}; #[test] fn infer_block_expr_type_mismatch() { @@ -858,3 +858,57 @@ fn coerce_unsize_generic() { "]], ); } + +#[test] +fn infer_two_closures_lub() { + check_types( + r#" +fn foo(c: i32) { + let add = |a: i32, b: i32| a + b; + let sub = |a, b| a - b; + //^ |i32, i32| -> i32 + if c > 42 { add } else { sub }; + //^ fn(i32, i32) -> i32 +} + "#, + ) +} + +#[test] +fn infer_match_diverging_branch_1() { + check_types( + r#" +enum Result { Ok(T), Err } +fn parse() -> T { loop {} } + +fn test() -> i32 { + let a = match parse() { + Ok(val) => val, + Err => return 0, + }; + a + //^ i32 +} + "#, + ) +} + +#[test] +fn infer_match_diverging_branch_2() { + // same as 1 except for order of branches + check_types( + r#" +enum Result { Ok(T), Err } +fn parse() -> T { loop {} } + +fn test() -> i32 { + let a = match parse() { + Err => return 0, + Ok(val) => val, + }; + a + //^ i32 +} + "#, + ) +} diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index ddbadbe4007..cd08b5c7a57 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs @@ -747,7 +747,7 @@ fn foo(tuple: (u8, i16, f32)) { 209..210 '_': (u8, i16, f32) 214..216 '{}': () 136..142: expected (u8, i16, f32), got (u8, i16) - 170..182: expected (u8, i16, f32), got (u8, i16, f32, _) + 170..182: expected (u8, i16, f32), got (u8, i16, f32, {unknown}) "#]], ); } diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 4318617124f..ad9edf11cd7 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -86,8 +86,6 @@ fn bug_651() { #[test] fn recursive_vars() { - cov_mark::check!(type_var_cycles_resolve_completely); - cov_mark::check!(type_var_cycles_resolve_as_possible); check_infer( r#" fn test() { @@ -97,12 +95,12 @@ fn recursive_vars() { "#, expect![[r#" 10..47 '{ ...&y]; }': () - 20..21 'y': &{unknown} - 24..31 'unknown': &{unknown} - 37..44 '[y, &y]': [&&{unknown}; 2] - 38..39 'y': &{unknown} - 41..43 '&y': &&{unknown} - 42..43 'y': &{unknown} + 20..21 'y': {unknown} + 24..31 'unknown': {unknown} + 37..44 '[y, &y]': [{unknown}; 2] + 38..39 'y': {unknown} + 41..43 '&y': &{unknown} + 42..43 'y': {unknown} "#]], ); } @@ -119,19 +117,19 @@ fn recursive_vars_2() { "#, expect![[r#" 10..79 '{ ...x)]; }': () - 20..21 'x': &&{unknown} - 24..31 'unknown': &&{unknown} - 41..42 'y': &&{unknown} - 45..52 'unknown': &&{unknown} - 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); 2] - 59..65 '(x, y)': (&&&{unknown}, &&&{unknown}) - 60..61 'x': &&{unknown} - 63..64 'y': &&{unknown} - 67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown}) - 68..70 '&y': &&&{unknown} - 69..70 'y': &&{unknown} - 72..74 '&x': &&&{unknown} - 73..74 'x': &&{unknown} + 20..21 'x': &{unknown} + 24..31 'unknown': &{unknown} + 41..42 'y': {unknown} + 45..52 'unknown': {unknown} + 58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2] + 59..65 '(x, y)': (&{unknown}, {unknown}) + 60..61 'x': &{unknown} + 63..64 'y': {unknown} + 67..75 '(&y, &x)': (&{unknown}, {unknown}) + 68..70 '&y': &{unknown} + 69..70 'y': {unknown} + 72..74 '&x': &&{unknown} + 73..74 'x': &{unknown} "#]], ); } @@ -165,7 +163,6 @@ fn infer_std_crash_1() { #[test] fn infer_std_crash_2() { - cov_mark::check!(type_var_resolves_to_int_var); // caused "equating two type variables, ...", taken from std check_infer( r#" @@ -257,27 +254,27 @@ fn infer_std_crash_5() { expect![[r#" 26..322 '{ ... } }': () 32..320 'for co... }': () - 36..43 'content': &{unknown} + 36..43 'content': {unknown} 47..60 'doesnt_matter': {unknown} 61..320 '{ ... }': () - 75..79 'name': &&{unknown} - 82..166 'if doe... }': &&{unknown} + 75..79 'name': &{unknown} + 82..166 'if doe... }': &{unknown} 85..98 'doesnt_matter': bool - 99..128 '{ ... }': &&{unknown} - 113..118 'first': &&{unknown} - 134..166 '{ ... }': &&{unknown} - 148..156 '&content': &&{unknown} - 149..156 'content': &{unknown} + 99..128 '{ ... }': &{unknown} + 113..118 'first': &{unknown} + 134..166 '{ ... }': &{unknown} + 148..156 '&content': &{unknown} + 149..156 'content': {unknown} 181..188 'content': &{unknown} 191..313 'if ICE... }': &{unknown} 194..231 'ICE_RE..._VALUE': {unknown} 194..247 'ICE_RE...&name)': bool - 241..246 '&name': &&&{unknown} - 242..246 'name': &&{unknown} - 248..276 '{ ... }': &&{unknown} - 262..266 'name': &&{unknown} - 282..313 '{ ... }': &{unknown} - 296..303 'content': &{unknown} + 241..246 '&name': &&{unknown} + 242..246 'name': &{unknown} + 248..276 '{ ... }': &{unknown} + 262..266 'name': &{unknown} + 282..313 '{ ... }': {unknown} + 296..303 'content': {unknown} "#]], ); } diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a9cd42186ed..5c70a1fc01c 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -1039,42 +1039,6 @@ fn infer_in_elseif() { ) } -#[test] -fn infer_closure_unify() { - check_infer( - r#" - fn foo(f: bool) { - let a = |x| x; - let b = |x| x; - let id = if f { a } else { b }; - id(123); - } - "#, - expect![[r#" - 7..8 'f': bool - 16..106 '{ ...23); }': () - 26..27 'a': |i32| -> i32 - 30..35 '|x| x': |i32| -> i32 - 31..32 'x': i32 - 34..35 'x': i32 - 45..46 'b': |i32| -> i32 - 49..54 '|x| x': |i32| -> i32 - 50..51 'x': i32 - 53..54 'x': i32 - 64..66 'id': |i32| -> i32 - 69..90 'if f {... { b }': |i32| -> i32 - 72..73 'f': bool - 74..79 '{ a }': |i32| -> i32 - 76..77 'a': |i32| -> i32 - 85..90 '{ b }': |i32| -> i32 - 87..88 'b': |i32| -> i32 - 96..98 'id': |i32| -> i32 - 96..103 'id(123)': i32 - 99..102 '123': i32 - "#]], - ) -} - #[test] fn infer_if_match_with_return() { check_infer( diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index f80cf987985..a5a2df54cb6 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs @@ -3104,7 +3104,7 @@ fn foo() { 568..573 'f(&s)': FnOnce::Output), (&Option,)> 570..572 '&s': &Option 571..572 's': Option - 549..562: expected Box)>, got Box<|_| -> ()> + 549..562: expected Box)>, got Box<|{unknown}| -> ()> "#]], ); } diff --git a/crates/hir_ty/src/tls.rs b/crates/hir_ty/src/tls.rs index 87c671a422c..708797c4772 100644 --- a/crates/hir_ty/src/tls.rs +++ b/crates/hir_ty/src/tls.rs @@ -1,7 +1,7 @@ //! Implementation of Chalk debug helper functions using TLS. -use std::fmt; +use std::fmt::{self, Debug}; -use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication}; +use chalk_ir::AliasTy; use itertools::Itertools; use crate::{ @@ -53,14 +53,6 @@ impl DebugContext<'_> { write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) } - pub(crate) fn debug_opaque_ty_id( - &self, - opaque_ty_id: chalk_ir::OpaqueTyId, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish() - } - pub(crate) fn debug_alias( &self, alias_ty: &AliasTy, @@ -68,7 +60,7 @@ impl DebugContext<'_> { ) -> Result<(), fmt::Error> { match alias_ty { AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt), - AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt), + AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(fmt), } } @@ -96,79 +88,6 @@ impl DebugContext<'_> { write!(fmt, ">::{}", type_alias_data.name) } - pub(crate) fn debug_opaque_ty( - &self, - opaque_ty: &chalk_ir::OpaqueTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", opaque_ty.opaque_ty_id) - } - - pub(crate) fn debug_ty( - &self, - ty: &chalk_ir::Ty, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", ty.data(&Interner)) - } - - pub(crate) fn debug_lifetime( - &self, - lifetime: &Lifetime, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", lifetime.data(&Interner)) - } - - pub(crate) fn debug_generic_arg( - &self, - parameter: &GenericArg, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) - } - - pub(crate) fn debug_goal( - &self, - goal: &Goal, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let goal_data = goal.data(&Interner); - write!(fmt, "{:?}", goal_data) - } - - pub(crate) fn debug_goals( - &self, - goals: &Goals, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", goals.debug(&Interner)) - } - - pub(crate) fn debug_program_clause_implication( - &self, - pci: &ProgramClauseImplication, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", pci.debug(&Interner)) - } - - pub(crate) fn debug_substitution( - &self, - substitution: &chalk_ir::Substitution, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", substitution.debug(&Interner)) - } - - pub(crate) fn debug_separator_trait_ref( - &self, - separator_trait_ref: &chalk_ir::SeparatorTraitRef, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) - } - pub(crate) fn debug_fn_def_id( &self, fn_def_id: chalk_ir::FnDefId, @@ -190,57 +109,6 @@ impl DebugContext<'_> { } } } - - pub(crate) fn debug_const( - &self, - _constant: &chalk_ir::Const, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "const") - } - - pub(crate) fn debug_variable_kinds( - &self, - variable_kinds: &chalk_ir::VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", variable_kinds.as_slice(&Interner)) - } - pub(crate) fn debug_variable_kinds_with_angles( - &self, - variable_kinds: &chalk_ir::VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner)) - } - pub(crate) fn debug_canonical_var_kinds( - &self, - canonical_var_kinds: &chalk_ir::CanonicalVarKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner)) - } - pub(crate) fn debug_program_clause( - &self, - clause: &chalk_ir::ProgramClause, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", clause.data(&Interner)) - } - pub(crate) fn debug_program_clauses( - &self, - clauses: &chalk_ir::ProgramClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", clauses.as_slice(&Interner)) - } - pub(crate) fn debug_quantified_where_clauses( - &self, - clauses: &chalk_ir::QuantifiedWhereClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(fmt, "{:?}", clauses.as_slice(&Interner)) - } } mod unsafe_tls { diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs index 9936d080338..294cb531c8b 100644 --- a/crates/hir_ty/src/traits.rs +++ b/crates/hir_ty/src/traits.rs @@ -2,7 +2,7 @@ use std::env::var; -use chalk_ir::cast::Cast; +use chalk_ir::GoalData; use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; use base_db::CrateId; @@ -10,7 +10,7 @@ use hir_def::{lang_item::LangItemTarget, TraitId}; use stdx::panic_context; use crate::{ - db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, + db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause, }; @@ -38,6 +38,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver { /// we assume that `T: Default`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TraitEnvironment { + pub krate: CrateId, // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord, // but for now it's too annoying... pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, @@ -45,6 +46,14 @@ pub struct TraitEnvironment { } impl TraitEnvironment { + pub fn empty(krate: CrateId) -> Self { + TraitEnvironment { + krate, + traits_from_clauses: Vec::new(), + env: chalk_ir::Environment::new(&Interner), + } + } + pub(crate) fn traits_in_scope_from_clauses<'a>( &'a self, ty: &'a Ty, @@ -59,34 +68,25 @@ impl TraitEnvironment { } } -impl Default for TraitEnvironment { - fn default() -> Self { - TraitEnvironment { - traits_from_clauses: Vec::new(), - env: chalk_ir::Environment::new(&Interner), - } - } -} - /// Solve a trait goal using Chalk. pub(crate) fn trait_solve_query( db: &dyn HirDatabase, krate: CrateId, - goal: Canonical>, + goal: Canonical>, ) -> Option { - let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal { - DomainGoal::Holds(WhereClause::Implemented(it)) => { + let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(&Interner) { + GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { db.trait_data(it.hir_trait_id()).name.to_string() } - DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), + GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(), _ => "??".to_string(), }); - log::info!("trait_solve_query({})", goal.value.goal.display(db)); + log::info!("trait_solve_query({:?})", goal.value.goal); - if let DomainGoal::Holds(WhereClause::AliasEq(AliasEq { + if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), .. - })) = &goal.value.goal + }))) = &goal.value.goal.data(&Interner) { if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) { // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible @@ -94,11 +94,9 @@ pub(crate) fn trait_solve_query( } } - let canonical = goal.cast(&Interner); - // We currently don't deal with universes (I think / hope they're not yet // relevant for our use cases?) - let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; + let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; solve(db, krate, &u_canonical) } diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 1a762d3dc1f..6b04ee16487 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -323,7 +323,7 @@ fn compute_type_match( if completion_ty == expected_type { Some(CompletionRelevanceTypeMatch::Exact) - } else if expected_type.could_unify_with(completion_ty) { + } else if expected_type.could_unify_with(ctx.db, completion_ty) { Some(CompletionRelevanceTypeMatch::CouldUnify) } else { None