mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
134701885d
commit
31519bb394
83 changed files with 2092 additions and 626 deletions
|
@ -734,6 +734,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
|
||||
return (ty, Some(strukt.into()));
|
||||
}
|
||||
ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
|
||||
_ => return (self.err_ty(), None),
|
||||
},
|
||||
Some(ResolveValueResult::Partial(typens, unresolved)) => (typens, Some(unresolved)),
|
||||
|
@ -875,7 +876,10 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
|
||||
fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
|
||||
let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
|
||||
let trait_ = self
|
||||
.resolver
|
||||
.resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
|
||||
.or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
||||
}
|
||||
|
||||
|
|
|
@ -238,18 +238,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
})
|
||||
.intern(Interner)
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
let self_ty =
|
||||
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
QuantifiedWhereClauses::from_iter(
|
||||
Interner,
|
||||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
|
||||
)
|
||||
});
|
||||
let bounds = crate::make_single_type_binders(bounds);
|
||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
match self.impl_trait_mode {
|
||||
ImplTraitLoweringMode::Opaque => {
|
||||
|
@ -468,29 +457,10 @@ impl<'a> TyLoweringContext<'a> {
|
|||
}
|
||||
}
|
||||
0 => {
|
||||
let self_ty = Some(
|
||||
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
|
||||
.intern(Interner),
|
||||
);
|
||||
let trait_ref = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
ctx.lower_trait_ref_from_resolved_path(
|
||||
trait_,
|
||||
resolved_segment,
|
||||
self_ty,
|
||||
)
|
||||
});
|
||||
let dyn_ty = DynTy {
|
||||
bounds: crate::make_single_type_binders(
|
||||
QuantifiedWhereClauses::from_iter(
|
||||
Interner,
|
||||
Some(crate::wrap_empty_binders(WhereClause::Implemented(
|
||||
trait_ref,
|
||||
))),
|
||||
),
|
||||
),
|
||||
lifetime: static_lifetime(),
|
||||
};
|
||||
TyKind::Dyn(dyn_ty).intern(Interner)
|
||||
// Trait object type without dyn; this should be handled in upstream. See
|
||||
// `lower_path()`.
|
||||
stdx::never!("unexpected fully resolved trait path");
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
_ => {
|
||||
// FIXME report error (ambiguous associated type)
|
||||
|
@ -555,11 +525,20 @@ impl<'a> TyLoweringContext<'a> {
|
|||
let (ty, res) = self.lower_ty_ext(type_ref);
|
||||
return self.lower_ty_relative_path(ty, res, path.segments());
|
||||
}
|
||||
|
||||
let (resolution, remaining_index) =
|
||||
match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
|
||||
Some(it) => it,
|
||||
None => return (TyKind::Error.intern(Interner), None),
|
||||
};
|
||||
|
||||
if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
|
||||
// trait object type without dyn
|
||||
let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
|
||||
let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
|
||||
return (ty, None);
|
||||
}
|
||||
|
||||
let (resolved_segment, remaining_segments) = match remaining_index {
|
||||
None => (
|
||||
path.segments().last().expect("resolved path has at least one element"),
|
||||
|
@ -987,6 +966,18 @@ impl<'a> TyLoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
QuantifiedWhereClauses::from_iter(
|
||||
Interner,
|
||||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
|
||||
)
|
||||
});
|
||||
let bounds = crate::make_single_type_binders(bounds);
|
||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||
}
|
||||
|
||||
fn lower_impl_trait(
|
||||
&self,
|
||||
bounds: &[Interned<TypeBound>],
|
||||
|
|
|
@ -1064,6 +1064,14 @@ pub fn resolve_indexing_op(
|
|||
None
|
||||
}
|
||||
|
||||
macro_rules! check_that {
|
||||
($cond:expr) => {
|
||||
if !$cond {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn is_valid_candidate(
|
||||
table: &mut InferenceTable<'_>,
|
||||
name: Option<&Name>,
|
||||
|
@ -1072,54 +1080,10 @@ fn is_valid_candidate(
|
|||
self_ty: &Ty,
|
||||
visible_from_module: Option<ModuleId>,
|
||||
) -> bool {
|
||||
macro_rules! check_that {
|
||||
($cond:expr) => {
|
||||
if !$cond {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let db = table.db;
|
||||
match item {
|
||||
AssocItemId::FunctionId(m) => {
|
||||
let data = db.function_data(m);
|
||||
|
||||
check_that!(name.map_or(true, |n| n == &data.name));
|
||||
check_that!(visible_from_module.map_or(true, |from_module| {
|
||||
let v = db.function_visibility(m).is_visible_from(db.upcast(), from_module);
|
||||
if !v {
|
||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||
}
|
||||
v
|
||||
}));
|
||||
|
||||
table.run_in_snapshot(|table| {
|
||||
let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build();
|
||||
let expect_self_ty = match m.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(_) => {
|
||||
subst.at(Interner, 0).assert_ty_ref(Interner).clone()
|
||||
}
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
|
||||
}
|
||||
// We should only get called for associated items (impl/trait)
|
||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||
if let Some(receiver_ty) = receiver_ty {
|
||||
check_that!(data.has_self_param());
|
||||
|
||||
let sig = db.callable_item_signature(m.into());
|
||||
let expected_receiver =
|
||||
sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst);
|
||||
|
||||
check_that!(table.unify(&receiver_ty, &expected_receiver));
|
||||
}
|
||||
true
|
||||
})
|
||||
is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
|
||||
}
|
||||
AssocItemId::ConstId(c) => {
|
||||
let data = db.const_data(c);
|
||||
|
@ -1152,6 +1116,94 @@ fn is_valid_candidate(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_valid_fn_candidate(
|
||||
table: &mut InferenceTable<'_>,
|
||||
fn_id: FunctionId,
|
||||
name: Option<&Name>,
|
||||
receiver_ty: Option<&Ty>,
|
||||
self_ty: &Ty,
|
||||
visible_from_module: Option<ModuleId>,
|
||||
) -> bool {
|
||||
let db = table.db;
|
||||
let data = db.function_data(fn_id);
|
||||
|
||||
check_that!(name.map_or(true, |n| n == &data.name));
|
||||
check_that!(visible_from_module.map_or(true, |from_module| {
|
||||
let v = db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module);
|
||||
if !v {
|
||||
cov_mark::hit!(autoderef_candidate_not_visible);
|
||||
}
|
||||
v
|
||||
}));
|
||||
|
||||
table.run_in_snapshot(|table| {
|
||||
let container = fn_id.lookup(db.upcast()).container;
|
||||
let impl_subst = match container {
|
||||
ItemContainerId::ImplId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
}
|
||||
ItemContainerId::TraitId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id)
|
||||
.use_parent_substs(&impl_subst)
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
|
||||
let expect_self_ty = match container {
|
||||
ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
|
||||
}
|
||||
// We should only get called for associated items (impl/trait)
|
||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||
|
||||
if let Some(receiver_ty) = receiver_ty {
|
||||
check_that!(data.has_self_param());
|
||||
|
||||
let sig = db.callable_item_signature(fn_id.into());
|
||||
let expected_receiver =
|
||||
sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
|
||||
|
||||
check_that!(table.unify(&receiver_ty, &expected_receiver));
|
||||
}
|
||||
|
||||
if let ItemContainerId::ImplId(impl_id) = container {
|
||||
// We need to consider the bounds on the impl to distinguish functions of the same name
|
||||
// for a type.
|
||||
let predicates = db.generic_predicates(impl_id.into());
|
||||
predicates
|
||||
.iter()
|
||||
.map(|predicate| {
|
||||
let (p, b) = predicate
|
||||
.clone()
|
||||
.substitute(Interner, &impl_subst)
|
||||
// Skipping the inner binders is ok, as we don't handle quantified where
|
||||
// clauses yet.
|
||||
.into_value_and_skipped_binders();
|
||||
stdx::always!(b.len(Interner) == 0);
|
||||
p
|
||||
})
|
||||
// It's ok to get ambiguity here, as we may not have enough information to prove
|
||||
// obligations. We'll check if the user is calling the selected method properly
|
||||
// later anyway.
|
||||
.all(|p| table.try_obligation(p.cast(Interner)).is_some())
|
||||
} else {
|
||||
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
|
||||
// `iterate_trait_method_candidates()`.
|
||||
// For others, this function shouldn't be called.
|
||||
true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn implements_trait(
|
||||
ty: &Canonical<Ty>,
|
||||
db: &dyn HirDatabase,
|
||||
|
|
|
@ -1790,3 +1790,46 @@ impl u16 {
|
|||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_impl_bounds() {
|
||||
check_types(
|
||||
r#"
|
||||
trait Trait {}
|
||||
struct Foo<T>(T);
|
||||
impl Trait for isize {}
|
||||
|
||||
impl<T: Trait> Foo<T> {
|
||||
fn foo() -> isize { 0 }
|
||||
fn bar(&self) -> isize { 0 }
|
||||
}
|
||||
|
||||
impl Foo<()> {
|
||||
fn foo() {}
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let _ = Foo::<isize>::foo();
|
||||
//^isize
|
||||
let _ = Foo(0isize).bar();
|
||||
//^isize
|
||||
let _ = Foo::<()>::foo();
|
||||
//^()
|
||||
let _ = Foo(()).bar();
|
||||
//^()
|
||||
let _ = Foo::<usize>::foo();
|
||||
//^{unknown}
|
||||
let _ = Foo(0usize).bar();
|
||||
//^{unknown}
|
||||
}
|
||||
|
||||
fn g<T: Trait>(a: T) {
|
||||
let _ = Foo::<T>::foo();
|
||||
//^isize
|
||||
let _ = Foo(a).bar();
|
||||
//^isize
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -488,6 +488,42 @@ fn infer_adt_pattern() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tuple_struct_destructured_with_self() {
|
||||
check_infer(
|
||||
r#"
|
||||
struct Foo(usize,);
|
||||
impl Foo {
|
||||
fn f() {
|
||||
let Self(s,) = &Foo(0,);
|
||||
let Self(s,) = &mut Foo(0,);
|
||||
let Self(s,) = Foo(0,);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
42..151 '{ ... }': ()
|
||||
56..64 'Self(s,)': Foo
|
||||
61..62 's': &usize
|
||||
67..75 '&Foo(0,)': &Foo
|
||||
68..71 'Foo': Foo(usize) -> Foo
|
||||
68..75 'Foo(0,)': Foo
|
||||
72..73 '0': usize
|
||||
89..97 'Self(s,)': Foo
|
||||
94..95 's': &mut usize
|
||||
100..112 '&mut Foo(0,)': &mut Foo
|
||||
105..108 'Foo': Foo(usize) -> Foo
|
||||
105..112 'Foo(0,)': Foo
|
||||
109..110 '0': usize
|
||||
126..134 'Self(s,)': Foo
|
||||
131..132 's': usize
|
||||
137..140 'Foo': Foo(usize) -> Foo
|
||||
137..144 'Foo(0,)': Foo
|
||||
141..142 '0': usize
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_variant_through_self_in_pattern() {
|
||||
check_infer(
|
||||
|
|
|
@ -1648,3 +1648,20 @@ fn main() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_empty_macro() {
|
||||
cov_mark::check!(empty_macro_in_trailing_position_is_removed);
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
macro_rules! m2 {
|
||||
($($t:tt)*) => {$($t)*};
|
||||
}
|
||||
|
||||
fn macrostmts() -> u8 {
|
||||
m2! { 0 }
|
||||
m2! {}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,31 @@ fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_future_trait() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: future
|
||||
struct Futurable;
|
||||
impl core::future::IntoFuture for Futurable {
|
||||
type Output = u64;
|
||||
type IntoFuture = IntFuture;
|
||||
}
|
||||
|
||||
struct IntFuture;
|
||||
impl core::future::Future for IntFuture {
|
||||
type Output = u64;
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let r = Futurable;
|
||||
let v = r.await;
|
||||
v;
|
||||
} //^ u64
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_try() {
|
||||
check_types(
|
||||
|
@ -1476,6 +1501,34 @@ fn test(x: Trait, y: &Trait) -> u64 {
|
|||
165..172 'z.foo()': u64
|
||||
"#]],
|
||||
);
|
||||
|
||||
check_infer_with_mismatches(
|
||||
r#"
|
||||
//- minicore: fn, coerce_unsized
|
||||
struct S;
|
||||
impl S {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
fn f(_: &Fn(S)) {}
|
||||
fn main() {
|
||||
f(&|number| number.foo());
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
31..35 'self': &S
|
||||
37..39 '{}': ()
|
||||
47..48 '_': &dyn Fn(S)
|
||||
58..60 '{}': ()
|
||||
71..105 '{ ...()); }': ()
|
||||
77..78 'f': fn f(&dyn Fn(S))
|
||||
77..102 'f(&|nu...foo())': ()
|
||||
79..101 '&|numb....foo()': &|S| -> ()
|
||||
80..101 '|numbe....foo()': |S| -> ()
|
||||
81..87 'number': S
|
||||
89..95 'number': S
|
||||
89..101 'number.foo()': ()
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue