mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
8536eb016c
commit
a99a48e786
86 changed files with 3149 additions and 1653 deletions
|
@ -823,10 +823,10 @@ pub(super) fn generic_predicate_to_inline_bound(
|
|||
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
|
||||
}
|
||||
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
|
||||
if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in {
|
||||
let trait_ = projection_ty.trait_(db);
|
||||
if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
|
||||
return None;
|
||||
}
|
||||
let trait_ = projection_ty.trait_(db);
|
||||
let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
|
||||
.iter()
|
||||
.map(|ty| ty.clone().cast(Interner))
|
||||
|
|
|
@ -262,7 +262,7 @@ impl TyExt for Ty {
|
|||
WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(proj),
|
||||
ty: _,
|
||||
}) => &proj.self_type_parameter(Interner) == self,
|
||||
}) => &proj.self_type_parameter(db) == self,
|
||||
_ => false,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -333,6 +333,7 @@ impl TyExt for Ty {
|
|||
pub trait ProjectionTyExt {
|
||||
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
|
||||
fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
|
||||
fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
|
||||
}
|
||||
|
||||
impl ProjectionTyExt for ProjectionTy {
|
||||
|
@ -349,6 +350,10 @@ impl ProjectionTyExt for ProjectionTy {
|
|||
_ => panic!("projection ty without parent trait"),
|
||||
}
|
||||
}
|
||||
|
||||
fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
|
||||
self.trait_ref(db).self_type_parameter(Interner)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TraitRefExt {
|
||||
|
|
|
@ -291,7 +291,7 @@ impl HirDisplay for ProjectionTy {
|
|||
|
||||
let trait_ = f.db.trait_data(self.trait_(f.db));
|
||||
write!(f, "<")?;
|
||||
self.self_type_parameter(Interner).hir_fmt(f)?;
|
||||
self.self_type_parameter(f.db).hir_fmt(f)?;
|
||||
write!(f, " as {}", trait_.name)?;
|
||||
if self.substitution.len(Interner) > 1 {
|
||||
write!(f, "<")?;
|
||||
|
@ -731,7 +731,7 @@ impl HirDisplay for Ty {
|
|||
WhereClause::AliasEq(AliasEq {
|
||||
alias: AliasTy::Projection(proj),
|
||||
ty: _,
|
||||
}) => &proj.self_type_parameter(Interner) == self,
|
||||
}) => &proj.self_type_parameter(f.db) == self,
|
||||
_ => false,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -751,9 +751,19 @@ impl HirDisplay for Ty {
|
|||
}
|
||||
TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
|
||||
TyKind::Dyn(dyn_ty) => {
|
||||
// Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
|
||||
// FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
|
||||
// more efficient when either of them hits stable.
|
||||
let mut bounds: SmallVec<[_; 4]> =
|
||||
dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
|
||||
let (auto_traits, others): (SmallVec<[_; 4]>, _) =
|
||||
bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
|
||||
bounds.extend(others);
|
||||
bounds.extend(auto_traits);
|
||||
|
||||
write_bounds_like_dyn_trait_with_prefix(
|
||||
"dyn",
|
||||
dyn_ty.bounds.skip_binders().interned(),
|
||||
&bounds,
|
||||
SizedByDefault::NotSized,
|
||||
f,
|
||||
)?;
|
||||
|
|
|
@ -190,7 +190,9 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
|
|||
pub enum InferenceDiagnostic {
|
||||
NoSuchField { expr: ExprId },
|
||||
BreakOutsideOfLoop { expr: ExprId, is_break: bool },
|
||||
IncorrectTryTarget { expr: ExprId },
|
||||
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
|
||||
DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
|
||||
}
|
||||
|
||||
/// A mismatch between an expected and an inferred type.
|
||||
|
@ -905,17 +907,6 @@ impl<'a> InferenceContext<'a> {
|
|||
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
||||
}
|
||||
|
||||
fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
|
||||
// FIXME resolve via lang_item once try v2 is stable
|
||||
let path = path![core::ops::Try];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
let trait_data = self.db.trait_data(trait_);
|
||||
trait_data
|
||||
// FIXME remove once try v2 is stable
|
||||
.associated_type_by_name(&name![Ok])
|
||||
.or_else(|| trait_data.associated_type_by_name(&name![Output]))
|
||||
}
|
||||
|
||||
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
|
||||
let trait_ = self.resolve_lang_item(name![neg])?.as_trait()?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
||||
|
|
|
@ -19,24 +19,24 @@ use hir_def::{
|
|||
resolver::resolver_for_expr,
|
||||
ConstParamId, FieldId, ItemContainerId, Lookup,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use hir_expand::{name, name::Name};
|
||||
use stdx::always;
|
||||
use syntax::ast::RangeOp;
|
||||
|
||||
use crate::{
|
||||
autoderef::{self, Autoderef},
|
||||
consteval,
|
||||
infer::{coerce::CoerceMany, find_continuable, BreakableKind},
|
||||
infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
|
||||
lower::{
|
||||
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
||||
},
|
||||
mapping::{from_chalk, ToChalk},
|
||||
method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
|
||||
primitive::{self, UintTy},
|
||||
static_lifetime, to_chalk_trait_id,
|
||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id,
|
||||
utils::{generics, Generics},
|
||||
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
|
||||
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
|
||||
ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -564,9 +564,29 @@ impl<'a> InferenceContext<'a> {
|
|||
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
|
||||
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
|
||||
}
|
||||
Expr::Try { expr } => {
|
||||
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
|
||||
self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
|
||||
&Expr::Try { expr } => {
|
||||
let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
|
||||
match self.resolve_try_impl_for(inner_ty.clone()) {
|
||||
Some((_, Some((output, residual)))) => {
|
||||
if let Some((_trait, false)) =
|
||||
self.implements_from_residual(self.return_ty.clone(), residual)
|
||||
{
|
||||
self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
|
||||
expr: tgt_expr,
|
||||
});
|
||||
}
|
||||
output
|
||||
}
|
||||
Some((trait_, None)) => {
|
||||
self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
|
||||
expr,
|
||||
trait_,
|
||||
ty: inner_ty,
|
||||
});
|
||||
self.err_ty()
|
||||
}
|
||||
None => self.err_ty(),
|
||||
}
|
||||
}
|
||||
Expr::Cast { expr, type_ref } => {
|
||||
// FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
|
||||
|
@ -1530,4 +1550,67 @@ impl<'a> InferenceContext<'a> {
|
|||
let ctx = self.breakables.pop().expect("breakable stack broken");
|
||||
(ctx.may_break.then(|| ctx.coerce.complete()), res)
|
||||
}
|
||||
|
||||
/// Check whether `ty` implements `FromResidual<r>`
|
||||
fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
|
||||
let from_residual_trait = self
|
||||
.resolver
|
||||
.resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
|
||||
let r = GenericArgData::Ty(r).intern(Interner);
|
||||
let b = TyBuilder::trait_ref(self.db, from_residual_trait);
|
||||
if b.remaining() != 2 {
|
||||
return Some((from_residual_trait, false));
|
||||
}
|
||||
let trait_ref = b.push(ty).push(r).build();
|
||||
Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
|
||||
}
|
||||
|
||||
fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
|
||||
let path = path![core::ops::Try];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
|
||||
let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
|
||||
let substitution = trait_ref.substitution.clone();
|
||||
self.push_obligation(trait_ref.clone().cast(Interner));
|
||||
|
||||
let trait_data = self.db.trait_data(trait_);
|
||||
let output = trait_data.associated_type_by_name(&name![Output]);
|
||||
let residual = trait_data.associated_type_by_name(&name![Residual]);
|
||||
|
||||
let output_ty = match output {
|
||||
Some(output) => {
|
||||
let output_ty = self.table.new_type_var();
|
||||
let alias_eq = AliasEq {
|
||||
alias: AliasTy::Projection(ProjectionTy {
|
||||
associated_ty_id: to_assoc_type_id(output),
|
||||
substitution: substitution.clone(),
|
||||
}),
|
||||
ty: output_ty.clone(),
|
||||
};
|
||||
self.push_obligation(alias_eq.cast(Interner));
|
||||
output_ty
|
||||
}
|
||||
None => self.err_ty(),
|
||||
};
|
||||
let residual_ty = match residual {
|
||||
Some(residual) => {
|
||||
let residual_ty = self.table.new_type_var();
|
||||
let alias_eq = AliasEq {
|
||||
alias: AliasTy::Projection(ProjectionTy {
|
||||
associated_ty_id: to_assoc_type_id(residual),
|
||||
substitution,
|
||||
}),
|
||||
ty: residual_ty.clone(),
|
||||
};
|
||||
self.push_obligation(alias_eq.cast(Interner));
|
||||
residual_ty
|
||||
}
|
||||
None => self.err_ty(),
|
||||
};
|
||||
// FIXME: We are doing the work twice here I think?
|
||||
Some((
|
||||
trait_,
|
||||
self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
|
|||
|
||||
use chalk_ir::{
|
||||
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
|
||||
IntTy, NoSolution, TyVariableKind, UniverseIndex,
|
||||
IntTy, TyVariableKind, UniverseIndex,
|
||||
};
|
||||
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||
use ena::unify::UnifyKey;
|
||||
|
@ -331,7 +331,6 @@ impl<'a> InferenceTable<'a> {
|
|||
&mut resolve::Resolver { table: self, var_stack, fallback },
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
.expect("fold failed unexpectedly")
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
||||
|
@ -452,13 +451,14 @@ impl<'a> InferenceTable<'a> {
|
|||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
use chalk_ir::fold::TypeFolder;
|
||||
|
||||
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||
#[has_interner(Interner)]
|
||||
struct VarFudger<'a, 'b> {
|
||||
table: &'a mut InferenceTable<'b>,
|
||||
highest_known_var: InferenceVar,
|
||||
}
|
||||
impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
}
|
||||
|
@ -472,24 +472,24 @@ impl<'a> InferenceTable<'a> {
|
|||
var: chalk_ir::InferenceVar,
|
||||
kind: TyVariableKind,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
) -> chalk_ir::Ty<Interner> {
|
||||
if var < self.highest_known_var {
|
||||
var.to_ty(Interner, kind)
|
||||
} else {
|
||||
self.table.new_type_var()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_inference_lifetime(
|
||||
&mut self,
|
||||
var: chalk_ir::InferenceVar,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
) -> chalk_ir::Lifetime<Interner> {
|
||||
if var < self.highest_known_var {
|
||||
var.to_lifetime(Interner)
|
||||
} else {
|
||||
self.table.new_lifetime_var()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_inference_const(
|
||||
|
@ -497,12 +497,12 @@ impl<'a> InferenceTable<'a> {
|
|||
ty: chalk_ir::Ty<Interner>,
|
||||
var: chalk_ir::InferenceVar,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
) -> chalk_ir::Const<Interner> {
|
||||
if var < self.highest_known_var {
|
||||
var.to_const(Interner, ty)
|
||||
} else {
|
||||
self.table.new_const_var(ty)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,7 +512,6 @@ impl<'a> InferenceTable<'a> {
|
|||
self.rollback_to(snapshot);
|
||||
result
|
||||
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
|
||||
.expect("fold_with with VarFudger")
|
||||
}
|
||||
|
||||
/// This checks whether any of the free variables in the `canonicalized`
|
||||
|
@ -639,21 +638,24 @@ mod resolve {
|
|||
use chalk_ir::{
|
||||
cast::Cast,
|
||||
fold::{TypeFoldable, TypeFolder},
|
||||
Fallible, NoSolution,
|
||||
};
|
||||
use hir_def::type_ref::ConstScalar;
|
||||
|
||||
pub(super) struct Resolver<'a, 'b, F> {
|
||||
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||
#[has_interner(Interner)]
|
||||
pub(super) struct Resolver<
|
||||
'a,
|
||||
'b,
|
||||
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
|
||||
> {
|
||||
pub(super) table: &'a mut InferenceTable<'b>,
|
||||
pub(super) var_stack: &'a mut Vec<InferenceVar>,
|
||||
pub(super) fallback: F,
|
||||
}
|
||||
impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
|
||||
impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
|
||||
where
|
||||
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
|
||||
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
|
||||
{
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
}
|
||||
|
@ -667,20 +669,19 @@ mod resolve {
|
|||
var: InferenceVar,
|
||||
kind: TyVariableKind,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Ty> {
|
||||
) -> Ty {
|
||||
let var = self.table.var_unification_table.inference_var_root(var);
|
||||
if self.var_stack.contains(&var) {
|
||||
// recursive type
|
||||
let default = self.table.fallback_value(var, kind).cast(Interner);
|
||||
return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
|
||||
return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
|
||||
.assert_ty_ref(Interner)
|
||||
.clone());
|
||||
.clone();
|
||||
}
|
||||
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||
// known_ty may contain other variables that are known by now
|
||||
self.var_stack.push(var);
|
||||
let result =
|
||||
known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
|
||||
let result = known_ty.fold_with(self, outer_binder);
|
||||
self.var_stack.pop();
|
||||
result.assert_ty_ref(Interner).clone()
|
||||
} else {
|
||||
|
@ -689,7 +690,7 @@ mod resolve {
|
|||
.assert_ty_ref(Interner)
|
||||
.clone()
|
||||
};
|
||||
Ok(result)
|
||||
result
|
||||
}
|
||||
|
||||
fn fold_inference_const(
|
||||
|
@ -697,7 +698,7 @@ mod resolve {
|
|||
ty: Ty,
|
||||
var: InferenceVar,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Const> {
|
||||
) -> Const {
|
||||
let var = self.table.var_unification_table.inference_var_root(var);
|
||||
let default = ConstData {
|
||||
ty: ty.clone(),
|
||||
|
@ -707,35 +708,33 @@ mod resolve {
|
|||
.cast(Interner);
|
||||
if self.var_stack.contains(&var) {
|
||||
// recursive
|
||||
return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
||||
return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
||||
.assert_const_ref(Interner)
|
||||
.clone());
|
||||
.clone();
|
||||
}
|
||||
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||
if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||
// known_ty may contain other variables that are known by now
|
||||
self.var_stack.push(var);
|
||||
let result =
|
||||
known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
|
||||
let result = known_ty.fold_with(self, outer_binder);
|
||||
self.var_stack.pop();
|
||||
result.assert_const_ref(Interner).clone()
|
||||
} else {
|
||||
(self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
||||
.assert_const_ref(Interner)
|
||||
.clone()
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_inference_lifetime(
|
||||
&mut self,
|
||||
_var: InferenceVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Lifetime> {
|
||||
) -> Lifetime {
|
||||
// fall back all lifetimes to 'static -- currently we don't deal
|
||||
// with any lifetimes, but we can sometimes get some lifetime
|
||||
// variables through Chalk's unification, and this at least makes
|
||||
// sure we don't leak them outside of inference
|
||||
Ok(crate::static_lifetime())
|
||||
crate::static_lifetime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,13 +254,13 @@ impl CallableSig {
|
|||
}
|
||||
|
||||
impl TypeFoldable<Interner> for CallableSig {
|
||||
fn fold_with<E>(
|
||||
fn try_fold_with<E>(
|
||||
self,
|
||||
folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
|
||||
folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Result<Self, E> {
|
||||
let vec = self.params_and_return.to_vec();
|
||||
let folded = vec.fold_with(folder, outer_binder)?;
|
||||
let folded = vec.try_fold_with(folder, outer_binder)?;
|
||||
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
|
||||
}
|
||||
}
|
||||
|
@ -292,16 +292,19 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
|||
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||
for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||
) -> T {
|
||||
use chalk_ir::{fold::TypeFolder, Fallible};
|
||||
struct FreeVarFolder<F1, F2>(F1, F2);
|
||||
use chalk_ir::fold::TypeFolder;
|
||||
|
||||
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||
#[has_interner(Interner)]
|
||||
struct FreeVarFolder<
|
||||
F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||
>(F1, F2);
|
||||
impl<
|
||||
'i,
|
||||
F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
|
||||
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
|
||||
F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||
> TypeFolder<Interner> for FreeVarFolder<F1, F2>
|
||||
{
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
}
|
||||
|
@ -310,12 +313,8 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
|||
Interner
|
||||
}
|
||||
|
||||
fn fold_free_var_ty(
|
||||
&mut self,
|
||||
bound_var: BoundVar,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Ty> {
|
||||
Ok(self.0(bound_var, outer_binder))
|
||||
fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
|
||||
self.0(bound_var, outer_binder)
|
||||
}
|
||||
|
||||
fn fold_free_var_const(
|
||||
|
@ -323,12 +322,11 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
|||
ty: Ty,
|
||||
bound_var: BoundVar,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Const> {
|
||||
Ok(self.1(ty, bound_var, outer_binder))
|
||||
) -> Const {
|
||||
self.1(ty, bound_var, outer_binder)
|
||||
}
|
||||
}
|
||||
t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
|
||||
.expect("fold failed unexpectedly")
|
||||
}
|
||||
|
||||
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
|
||||
|
@ -351,16 +349,13 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
|
|||
f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
|
||||
binders: DebruijnIndex,
|
||||
) -> T {
|
||||
use chalk_ir::{
|
||||
fold::{TypeFolder, TypeSuperFoldable},
|
||||
Fallible,
|
||||
};
|
||||
struct TyFolder<F>(F);
|
||||
impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
|
||||
TypeFolder<Interner> for TyFolder<F>
|
||||
use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
|
||||
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||
#[has_interner(Interner)]
|
||||
struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
|
||||
impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
|
||||
for TyFolder<F>
|
||||
{
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
}
|
||||
|
@ -369,16 +364,16 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
|
|||
Interner
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
||||
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
|
||||
Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
|
||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
|
||||
let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
|
||||
self.0(Either::Left(ty), outer_binder).left().unwrap()
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
|
||||
Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
|
||||
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
|
||||
self.0(Either::Right(c), outer_binder).right().unwrap()
|
||||
}
|
||||
}
|
||||
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
|
||||
t.fold_with(&mut TyFolder(f), binders)
|
||||
}
|
||||
|
||||
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
|
||||
|
@ -390,16 +385,16 @@ where
|
|||
T: HasInterner<Interner = Interner>,
|
||||
{
|
||||
use chalk_ir::{
|
||||
fold::{TypeFolder, TypeSuperFoldable},
|
||||
fold::{FallibleTypeFolder, TypeSuperFoldable},
|
||||
Fallible,
|
||||
};
|
||||
struct ErrorReplacer {
|
||||
vars: usize,
|
||||
}
|
||||
impl TypeFolder<Interner> for ErrorReplacer {
|
||||
impl FallibleTypeFolder<Interner> for ErrorReplacer {
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||
fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -407,18 +402,17 @@ where
|
|||
Interner
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
||||
fn try_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)
|
||||
ty.try_super_fold_with(self.as_dyn(), outer_binder)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_inference_ty(
|
||||
fn try_fold_inference_ty(
|
||||
&mut self,
|
||||
_var: InferenceVar,
|
||||
_kind: TyVariableKind,
|
||||
|
@ -433,7 +427,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_free_var_ty(
|
||||
fn try_fold_free_var_ty(
|
||||
&mut self,
|
||||
_bound_var: BoundVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
|
@ -447,7 +441,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_inference_const(
|
||||
fn try_fold_inference_const(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
_var: InferenceVar,
|
||||
|
@ -460,7 +454,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_free_var_const(
|
||||
fn try_fold_free_var_const(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
_bound_var: BoundVar,
|
||||
|
@ -473,7 +467,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_inference_lifetime(
|
||||
fn try_fold_inference_lifetime(
|
||||
&mut self,
|
||||
_var: InferenceVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
|
@ -485,7 +479,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_free_var_lifetime(
|
||||
fn try_fold_free_var_lifetime(
|
||||
&mut self,
|
||||
_bound_var: BoundVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
|
@ -498,7 +492,7 @@ where
|
|||
}
|
||||
}
|
||||
let mut error_replacer = ErrorReplacer { vars: 0 };
|
||||
let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
|
||||
let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
|
||||
Ok(t) => t,
|
||||
Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
|
||||
};
|
||||
|
|
|
@ -1111,6 +1111,24 @@ pub fn resolve_indexing_op(
|
|||
}
|
||||
None
|
||||
}
|
||||
/// Returns the receiver type for the try branch trait call.
|
||||
pub fn resolve_branch_op(
|
||||
db: &dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
ty: Canonical<Ty>,
|
||||
try_trait: TraitId,
|
||||
) -> Option<ReceiverAdjustments> {
|
||||
let mut table = InferenceTable::new(db, env.clone());
|
||||
let ty = table.instantiate_canonical(ty);
|
||||
let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
|
||||
for (ty, adj) in deref_chain.into_iter().zip(adj) {
|
||||
let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
|
||||
if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
|
||||
return Some(adj);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
macro_rules! check_that {
|
||||
($cond:expr) => {
|
||||
|
|
|
@ -55,6 +55,28 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_dyn_ty_independent_of_order() {
|
||||
check_types_source_code(
|
||||
r#"
|
||||
auto trait Send {}
|
||||
trait A {
|
||||
type Assoc;
|
||||
}
|
||||
trait B: A {}
|
||||
|
||||
fn test(
|
||||
_: &(dyn A<Assoc = ()> + Send),
|
||||
//^ &(dyn A<Assoc = ()> + Send)
|
||||
_: &(dyn Send + A<Assoc = ()>),
|
||||
//^ &(dyn A<Assoc = ()> + Send)
|
||||
_: &dyn B<Assoc = ()>,
|
||||
//^ &(dyn B<Assoc = ()>)
|
||||
) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_dyn_for_ty() {
|
||||
// FIXME
|
||||
|
|
|
@ -1070,3 +1070,13 @@ fn main() {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_params() {
|
||||
check_types(
|
||||
r#"
|
||||
fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
|
||||
//^^^ u32
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -162,98 +162,16 @@ fn test() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_try() {
|
||||
check_types(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
fn test() {
|
||||
let r: Result<i32, u64> = Result::Ok(1);
|
||||
let v = r?;
|
||||
v;
|
||||
} //^ i32
|
||||
|
||||
//- /core.rs crate:core
|
||||
pub mod ops {
|
||||
pub trait Try {
|
||||
type Ok;
|
||||
type Error;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod result {
|
||||
pub enum Result<O, E> {
|
||||
Ok(O),
|
||||
Err(E)
|
||||
}
|
||||
|
||||
impl<O, E> crate::ops::Try for Result<O, E> {
|
||||
type Ok = O;
|
||||
type Error = E;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub mod rust_2018 {
|
||||
pub use crate::{result::*, ops::*};
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_try_trait_v2() {
|
||||
check_types(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
fn test() {
|
||||
let r: Result<i32, u64> = Result::Ok(1);
|
||||
//- minicore: try
|
||||
fn test() -> core::ops::ControlFlow<u32, f32> {
|
||||
let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
|
||||
let v = r?;
|
||||
v;
|
||||
} //^ i32
|
||||
|
||||
//- /core.rs crate:core
|
||||
mod ops {
|
||||
mod try_trait {
|
||||
pub trait Try: FromResidual {
|
||||
type Output;
|
||||
type Residual;
|
||||
}
|
||||
pub trait FromResidual<R = <Self as Try>::Residual> {}
|
||||
}
|
||||
|
||||
pub use self::try_trait::FromResidual;
|
||||
pub use self::try_trait::Try;
|
||||
}
|
||||
|
||||
mod convert {
|
||||
pub trait From<T> {}
|
||||
impl<T> From<T> for T {}
|
||||
}
|
||||
|
||||
pub mod result {
|
||||
use crate::convert::From;
|
||||
use crate::ops::{Try, FromResidual};
|
||||
|
||||
pub enum Infallible {}
|
||||
pub enum Result<O, E> {
|
||||
Ok(O),
|
||||
Err(E)
|
||||
}
|
||||
|
||||
impl<O, E> Try for Result<O, E> {
|
||||
type Output = O;
|
||||
type Error = Result<Infallible, E>;
|
||||
}
|
||||
|
||||
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub mod rust_2018 {
|
||||
pub use crate::result::*;
|
||||
}
|
||||
//^ f32
|
||||
r
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
|
@ -13,8 +13,8 @@ use syntax::SmolStr;
|
|||
|
||||
use crate::{
|
||||
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
|
||||
Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
|
||||
WhereClause,
|
||||
Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
|
||||
TyKind, WhereClause,
|
||||
};
|
||||
|
||||
/// This controls how much 'time' we give the Chalk solver before giving up.
|
||||
|
@ -95,7 +95,7 @@ pub(crate) fn trait_solve_query(
|
|||
..
|
||||
}))) = &goal.value.goal.data(Interner)
|
||||
{
|
||||
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
|
||||
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
|
||||
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
|
||||
return Some(Solution::Ambig(Guidance::Unknown));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue