mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
'inference': collect RPIT obligations
Collect obligations from RPITs (Return Position `impl Trait`) of a function which is being inferred. This allows inferring {unknown}s from RPIT bounds.
This commit is contained in:
parent
6262b60153
commit
970276b559
@ -19,7 +19,7 @@ use std::sync::Arc;
|
|||||||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::Body,
|
body::Body,
|
||||||
data::{ConstData, FunctionData, StaticData},
|
data::{ConstData, StaticData},
|
||||||
expr::{BindingAnnotation, ExprId, PatId},
|
expr::{BindingAnnotation, ExprId, PatId},
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
path::{path, Path},
|
path::{path, Path},
|
||||||
@ -32,12 +32,13 @@ use hir_expand::name::{name, Name};
|
|||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
use la_arena::ArenaMap;
|
use la_arena::ArenaMap;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use stdx::impl_from;
|
use stdx::{always, impl_from};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
|
||||||
to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, GenericArg, Goal, InEnvironment,
|
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
|
||||||
Interner, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, Substitution,
|
||||||
|
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This lint has a false positive here. See the link below for details.
|
// This lint has a false positive here. See the link below for details.
|
||||||
@ -64,7 +65,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
|||||||
|
|
||||||
match def {
|
match def {
|
||||||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
||||||
DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)),
|
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
|
||||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +458,8 @@ impl<'a> InferenceContext<'a> {
|
|||||||
self.return_ty = self.make_ty(&data.type_ref);
|
self.return_ty = self.make_ty(&data.type_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_fn(&mut self, data: &FunctionData) {
|
fn collect_fn(&mut self, func: FunctionId) {
|
||||||
|
let data = self.db.function_data(func);
|
||||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
|
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
|
||||||
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
|
.with_impl_trait_mode(ImplTraitLoweringMode::Param);
|
||||||
let param_tys =
|
let param_tys =
|
||||||
@ -474,8 +476,42 @@ impl<'a> InferenceContext<'a> {
|
|||||||
} else {
|
} else {
|
||||||
&*data.ret_type
|
&*data.ret_type
|
||||||
};
|
};
|
||||||
let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT
|
let return_ty = self.make_ty_with_mode(return_ty, ImplTraitLoweringMode::Opaque);
|
||||||
self.return_ty = return_ty;
|
self.return_ty = return_ty;
|
||||||
|
|
||||||
|
if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
||||||
|
// RPIT opaque types use substitution of their parent function.
|
||||||
|
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
||||||
|
self.return_ty = fold_tys(
|
||||||
|
self.return_ty.clone(),
|
||||||
|
|ty, _| {
|
||||||
|
let opaque_ty_id = match ty.kind(Interner) {
|
||||||
|
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
|
||||||
|
_ => return ty,
|
||||||
|
};
|
||||||
|
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
||||||
|
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let bounds = (*rpits).map_ref(|rpits| {
|
||||||
|
rpits.impl_traits[idx as usize].bounds.map_ref(|it| it.into_iter())
|
||||||
|
});
|
||||||
|
let var = self.table.new_type_var();
|
||||||
|
let var_subst = Substitution::from1(Interner, var.clone());
|
||||||
|
for bound in bounds {
|
||||||
|
let predicate =
|
||||||
|
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
|
||||||
|
let (var_predicate, binders) = predicate
|
||||||
|
.substitute(Interner, &var_subst)
|
||||||
|
.into_value_and_skipped_binders();
|
||||||
|
always!(binders.len(Interner) == 0); // quantified where clauses not yet handled
|
||||||
|
self.push_obligation(var_predicate.cast(Interner));
|
||||||
|
}
|
||||||
|
var
|
||||||
|
},
|
||||||
|
DebruijnIndex::INNERMOST,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_body(&mut self) {
|
fn infer_body(&mut self) {
|
||||||
|
@ -1255,6 +1255,32 @@ fn test() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_from_return_pos_impl_trait() {
|
||||||
|
check_infer_with_mismatches(
|
||||||
|
r#"
|
||||||
|
//- minicore: fn, sized
|
||||||
|
trait Trait<T> {}
|
||||||
|
struct Bar<T>(T);
|
||||||
|
impl<T> Trait<T> for Bar<T> {}
|
||||||
|
fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
|
||||||
|
(|input, t| {}, Bar(C))
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
134..165 '{ ...(C)) }': (|&str, T| -> (), Bar<u8>)
|
||||||
|
140..163 '(|inpu...ar(C))': (|&str, T| -> (), Bar<u8>)
|
||||||
|
141..154 '|input, t| {}': |&str, T| -> ()
|
||||||
|
142..147 'input': &str
|
||||||
|
149..150 't': T
|
||||||
|
152..154 '{}': ()
|
||||||
|
156..159 'Bar': Bar<u8>(u8) -> Bar<u8>
|
||||||
|
156..162 'Bar(C)': Bar<u8>
|
||||||
|
160..161 'C': u8
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dyn_trait() {
|
fn dyn_trait() {
|
||||||
check_infer(
|
check_infer(
|
||||||
@ -2392,7 +2418,7 @@ fn test() -> impl Trait<i32> {
|
|||||||
171..182 '{ loop {} }': T
|
171..182 '{ loop {} }': T
|
||||||
173..180 'loop {}': !
|
173..180 'loop {}': !
|
||||||
178..180 '{}': ()
|
178..180 '{}': ()
|
||||||
213..309 '{ ...t()) }': S<{unknown}>
|
213..309 '{ ...t()) }': S<i32>
|
||||||
223..225 's1': S<u32>
|
223..225 's1': S<u32>
|
||||||
228..229 'S': S<u32>(u32) -> S<u32>
|
228..229 'S': S<u32>(u32) -> S<u32>
|
||||||
228..240 'S(default())': S<u32>
|
228..240 'S(default())': S<u32>
|
||||||
@ -2408,10 +2434,10 @@ fn test() -> impl Trait<i32> {
|
|||||||
276..288 'S(default())': S<i32>
|
276..288 'S(default())': S<i32>
|
||||||
278..285 'default': fn default<i32>() -> i32
|
278..285 'default': fn default<i32>() -> i32
|
||||||
278..287 'default()': i32
|
278..287 'default()': i32
|
||||||
295..296 'S': S<{unknown}>({unknown}) -> S<{unknown}>
|
295..296 'S': S<i32>(i32) -> S<i32>
|
||||||
295..307 'S(default())': S<{unknown}>
|
295..307 'S(default())': S<i32>
|
||||||
297..304 'default': fn default<{unknown}>() -> {unknown}
|
297..304 'default': fn default<i32>() -> i32
|
||||||
297..306 'default()': {unknown}
|
297..306 'default()': i32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user