Merge #8856
8856: Use Chalk for unification r=flodiebold a=flodiebold - use Chalk's unification, get rid of our own `unify` - rewrite coercion to not use unification internals and to be more analogous to rustc - fix various coercion bugs - rewrite handling of obligations, since the old hacky optimization where we noted when an inference variable changes wasn't possible anymore - stop trying to deeply resolve types all the time during inference, instead only do it shallowly where necessary Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
edbde25ca2
@ -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<T>,
|
||||
) -> Option<T> {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -344,20 +344,20 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
||||
}
|
||||
|
||||
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
||||
self
|
||||
&self.db
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> chalk_ir::UnificationDatabase<Interner> for ChalkContext<'a> {
|
||||
impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
|
||||
fn fn_def_variance(
|
||||
&self,
|
||||
fn_def_id: chalk_ir::FnDefId<Interner>,
|
||||
) -> chalk_ir::Variances<Interner> {
|
||||
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<Interner>) -> chalk_ir::Variances<Interner> {
|
||||
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());
|
||||
|
@ -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<BuiltinType>;
|
||||
@ -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)),
|
||||
|
@ -117,10 +117,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||
fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>;
|
||||
|
||||
#[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<dyn DefDatabase> {
|
||||
fn trait_solve(
|
||||
&self,
|
||||
krate: CrateId,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
|
||||
) -> Option<crate::Solution>;
|
||||
|
||||
#[salsa::invoke(crate::traits::trait_solve_query)]
|
||||
fn trait_solve_query(
|
||||
&self,
|
||||
krate: CrateId,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
|
||||
) -> Option<crate::Solution>;
|
||||
|
||||
#[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
|
||||
@ -168,7 +168,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
|
||||
fn trait_solve_wait(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
|
||||
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
|
||||
) -> Option<crate::Solution> {
|
||||
let _p = profile::span("trait_solve::wait");
|
||||
db.trait_solve_query(krate, goal)
|
||||
|
@ -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<InEnvironment<Goal>>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TypeError;
|
||||
pub(crate) type InferResult = Result<InferOk, TypeError>;
|
||||
|
||||
/// 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<Body>,
|
||||
resolver: Resolver,
|
||||
table: unify::InferenceTable,
|
||||
table: unify::InferenceTable<'a>,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
obligations: Vec<DomainGoal>,
|
||||
last_obligations_check: Option<u32>,
|
||||
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<VariantId>) {
|
||||
@ -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<Ty> {
|
||||
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<Ty> {
|
||||
match self {
|
||||
Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
|
||||
// Expectation::Castable(_) |
|
||||
Expectation::RValueLikeUnsized(_) | Expectation::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,156 +2,414 @@
|
||||
//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions
|
||||
//! like going from `&Vec<T>` 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<ExprId>, 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<?T> = 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<T>` to `&'b mut [T]`.
|
||||
// In the autoderef loop for `&'a mut Vec<T>`, we would get
|
||||
// three callbacks:
|
||||
//
|
||||
// - `&'a mut Vec<T>` -- 0 derefs, just ignore it
|
||||
// - `Vec<T>` -- 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<T>`
|
||||
// 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<ty_ty>`
|
||||
///
|
||||
/// 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<bool> {
|
||||
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<B> for A` where
|
||||
// A and B have 'matching' fields. This rules out the following
|
||||
// two types of blanket impls:
|
||||
//
|
||||
// `impl<T> CoerceUnsized<T> for SomeType`
|
||||
// `impl<T> CoerceUnsized<SomeType> 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<T> CoerceUnsized<SomeType> for T`)
|
||||
// or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> 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<Target>`.
|
||||
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<DomainGoal> =
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -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>, 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>, 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());
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Substitution>)> {
|
||||
let ty = self.resolve_ty_shallow(ty);
|
||||
let (enum_id, subst) = match ty.as_adt() {
|
||||
Some((AdtId::EnumId(e), subst)) => (e, subst),
|
||||
_ => return None,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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>(T);
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for InternedWrapper<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for InternedWrapper<T> {
|
||||
type Target = T;
|
||||
|
||||
@ -101,66 +107,65 @@ impl chalk_ir::interner::Interner for Interner {
|
||||
opaque_ty: &chalk_ir::OpaqueTy<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
|
||||
tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
|
||||
Some(write!(fmt, "{:?}", ty.data(&Interner)))
|
||||
}
|
||||
|
||||
fn debug_lifetime(
|
||||
lifetime: &chalk_ir::Lifetime<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<fmt::Result> {
|
||||
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<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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<Self>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Option<fmt::Result> {
|
||||
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>) -> Self::InternedType {
|
||||
|
@ -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<Interner>;
|
||||
|
||||
pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
|
||||
pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
|
||||
pub type Goal = chalk_ir::Goal<Interner>;
|
||||
pub type AliasEq = chalk_ir::AliasEq<Interner>;
|
||||
pub type Solution = chalk_solve::Solution<Interner>;
|
||||
pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
|
||||
@ -167,6 +169,7 @@ pub fn make_canonical<T: HasInterner<Interner = Interner>>(
|
||||
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<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
||||
}
|
||||
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
|
||||
}
|
||||
|
||||
pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result>
|
||||
where
|
||||
T: HasInterner<Interner = Interner> + Fold<Interner>,
|
||||
T::Result: HasInterner<Interner = Interner>,
|
||||
{
|
||||
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<Ty> {
|
||||
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<Ty> {
|
||||
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) }
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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<Ty>,
|
||||
db: &dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
name: Option<&Name>,
|
||||
receiver_ty: Option<&Canonical<Ty>>,
|
||||
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<TraitEnvironment>,
|
||||
name: Option<&Name>,
|
||||
receiver_ty: Option<&Canonical<Ty>>,
|
||||
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<TraitEnvironment>,
|
||||
impl_id: ImplId,
|
||||
self_ty: &Canonical<Ty>,
|
||||
) -> Option<Substitution> {
|
||||
@ -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<TraitEnvironment>,
|
||||
function_id: FunctionId,
|
||||
self_ty: &Canonical<Ty>,
|
||||
) -> Option<Ty> {
|
||||
@ -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(_)))
|
||||
}
|
||||
|
@ -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<T> { Ok(T), Err }
|
||||
fn parse<T>() -> 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<T> { Ok(T), Err }
|
||||
fn parse<T>() -> T { loop {} }
|
||||
|
||||
fn test() -> i32 {
|
||||
let a = match parse() {
|
||||
Err => return 0,
|
||||
Ok(val) => val,
|
||||
};
|
||||
a
|
||||
//^ i32
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
@ -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})
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -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}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -3104,7 +3104,7 @@ fn foo() {
|
||||
568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
|
||||
570..572 '&s': &Option<i32>
|
||||
571..572 's': Option<i32>
|
||||
549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|_| -> ()>
|
||||
549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -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<Interner>,
|
||||
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<Interner>,
|
||||
@ -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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
|
||||
}
|
||||
|
||||
pub(crate) fn debug_ty(
|
||||
&self,
|
||||
ty: &chalk_ir::Ty<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", ty.data(&Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn debug_lifetime(
|
||||
&self,
|
||||
lifetime: &Lifetime<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", lifetime.data(&Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn debug_generic_arg(
|
||||
&self,
|
||||
parameter: &GenericArg<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
|
||||
}
|
||||
|
||||
pub(crate) fn debug_goal(
|
||||
&self,
|
||||
goal: &Goal<Interner>,
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", goals.debug(&Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn debug_program_clause_implication(
|
||||
&self,
|
||||
pci: &ProgramClauseImplication<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "{:?}", pci.debug(&Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn debug_substitution(
|
||||
&self,
|
||||
substitution: &chalk_ir::Substitution<Interner>,
|
||||
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<Interner>,
|
||||
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<Interner>,
|
||||
@ -190,57 +109,6 @@ impl DebugContext<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn debug_const(
|
||||
&self,
|
||||
_constant: &chalk_ir::Const<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(fmt, "const")
|
||||
}
|
||||
|
||||
pub(crate) fn debug_variable_kinds(
|
||||
&self,
|
||||
variable_kinds: &chalk_ir::VariableKinds<Interner>,
|
||||
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<Interner>,
|
||||
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<Interner>,
|
||||
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<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(fmt, "{:?}", clause.data(&Interner))
|
||||
}
|
||||
pub(crate) fn debug_program_clauses(
|
||||
&self,
|
||||
clauses: &chalk_ir::ProgramClauses<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(fmt, "{:?}", clauses.as_slice(&Interner))
|
||||
}
|
||||
pub(crate) fn debug_quantified_where_clauses(
|
||||
&self,
|
||||
clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
write!(fmt, "{:?}", clauses.as_slice(&Interner))
|
||||
}
|
||||
}
|
||||
|
||||
mod unsafe_tls {
|
||||
|
@ -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<Interner> {
|
||||
/// 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<InEnvironment<DomainGoal>>,
|
||||
goal: Canonical<InEnvironment<Goal>>,
|
||||
) -> Option<Solution> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user