mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
1721: Impl/dyn trait r=flodiebold a=flodiebold This adds support for `impl Trait` and `dyn Trait` types as far as possible without Chalk. So we can represent them in the type system, and handle them in method resolution, but Chalk doesn't know about them yet. There's a small temporary hack here where we bypass Chalk during method resolution, so we can handle simple method calls on them and completion works. Fixes #1608. 1723: Make sysroot use `RUST_SRC_PATH` if set r=matklad a=bkchr Co-authored-by: Florian Diebold <flodiebold@gmail.com> Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
commit
0c35d82329
11 changed files with 471 additions and 55 deletions
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||||
name::SELF_TYPE,
|
name::SELF_TYPE,
|
||||||
path::Path,
|
path::Path,
|
||||||
type_ref::TypeRef,
|
type_ref::{TypeBound, TypeRef},
|
||||||
AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
|
AdtDef, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
|
||||||
Trait, TypeAlias, Union,
|
Trait, TypeAlias, Union,
|
||||||
};
|
};
|
||||||
|
@ -35,10 +35,12 @@ pub struct GenericParams {
|
||||||
|
|
||||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||||
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
||||||
|
/// It might still result in multiple actual predicates though, because of
|
||||||
|
/// associated type bindings like `Iterator<Item = u32>`.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct WherePredicate {
|
pub struct WherePredicate {
|
||||||
pub(crate) type_ref: TypeRef,
|
pub(crate) type_ref: TypeRef,
|
||||||
pub(crate) trait_ref: Path,
|
pub(crate) bound: TypeBound,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
|
// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
|
||||||
|
@ -143,18 +145,8 @@ impl GenericParams {
|
||||||
// FIXME: remove this bound
|
// FIXME: remove this bound
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let path = bound
|
let bound = TypeBound::from_ast(bound);
|
||||||
.type_ref()
|
self.where_predicates.push(WherePredicate { type_ref, bound });
|
||||||
.and_then(|tr| match tr {
|
|
||||||
ast::TypeRef::PathType(path) => path.path(),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.and_then(Path::from_ast);
|
|
||||||
let path = match path {
|
|
||||||
Some(p) => p,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
|
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
|
||||||
|
|
|
@ -161,14 +161,28 @@ pub enum Ty {
|
||||||
name: Name,
|
name: Name,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A bound type variable. Only used during trait resolution to represent
|
/// A bound type variable. Used during trait resolution to represent Chalk
|
||||||
/// Chalk variables.
|
/// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
|
||||||
Bound(u32),
|
Bound(u32),
|
||||||
|
|
||||||
/// A type variable used during type checking. Not to be confused with a
|
/// A type variable used during type checking. Not to be confused with a
|
||||||
/// type parameter.
|
/// type parameter.
|
||||||
Infer(InferTy),
|
Infer(InferTy),
|
||||||
|
|
||||||
|
/// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
|
||||||
|
///
|
||||||
|
/// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
|
||||||
|
/// represents the `Self` type inside the bounds. This is currently
|
||||||
|
/// implicit; Chalk has the `Binders` struct to make it explicit, but it
|
||||||
|
/// didn't seem worth the overhead yet.
|
||||||
|
Dyn(Arc<[GenericPredicate]>),
|
||||||
|
|
||||||
|
/// An opaque type (`impl Trait`).
|
||||||
|
///
|
||||||
|
/// The predicates are quantified over the `Self` type; see `Ty::Dyn` for
|
||||||
|
/// more.
|
||||||
|
Opaque(Arc<[GenericPredicate]>),
|
||||||
|
|
||||||
/// A placeholder for a type which could not be computed; this is propagated
|
/// A placeholder for a type which could not be computed; this is propagated
|
||||||
/// to avoid useless error messages. Doubles as a placeholder where type
|
/// to avoid useless error messages. Doubles as a placeholder where type
|
||||||
/// variables are inserted before type checking, since we want to try to
|
/// variables are inserted before type checking, since we want to try to
|
||||||
|
@ -194,6 +208,12 @@ impl Substs {
|
||||||
Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into())
|
Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||||
|
for t in self.0.iter() {
|
||||||
|
t.walk(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||||
let mut v: Vec<_> = self.0.iter().cloned().collect();
|
let mut v: Vec<_> = self.0.iter().cloned().collect();
|
||||||
|
@ -270,6 +290,14 @@ impl TraitRef {
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||||
|
self.substs.walk(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||||
|
self.substs.walk_mut(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
|
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
|
||||||
|
@ -299,6 +327,20 @@ impl GenericPredicate {
|
||||||
GenericPredicate::Error => self,
|
GenericPredicate::Error => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
|
||||||
|
match self {
|
||||||
|
GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
|
||||||
|
GenericPredicate::Error => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||||
|
match self {
|
||||||
|
GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
|
||||||
|
GenericPredicate::Error => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basically a claim (currently not validated / checked) that the contained
|
/// Basically a claim (currently not validated / checked) that the contained
|
||||||
|
@ -386,6 +428,11 @@ impl Ty {
|
||||||
t.walk(f);
|
t.walk(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||||
|
for p in predicates.iter() {
|
||||||
|
p.walk(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||||
}
|
}
|
||||||
f(self);
|
f(self);
|
||||||
|
@ -402,6 +449,13 @@ impl Ty {
|
||||||
Ty::UnselectedProjection(p_ty) => {
|
Ty::UnselectedProjection(p_ty) => {
|
||||||
p_ty.parameters.walk_mut(f);
|
p_ty.parameters.walk_mut(f);
|
||||||
}
|
}
|
||||||
|
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||||
|
let mut v: Vec<_> = predicates.iter().cloned().collect();
|
||||||
|
for p in &mut v {
|
||||||
|
p.walk_mut(f);
|
||||||
|
}
|
||||||
|
*predicates = v.into();
|
||||||
|
}
|
||||||
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
|
||||||
}
|
}
|
||||||
f(self);
|
f(self);
|
||||||
|
@ -529,6 +583,19 @@ impl Ty {
|
||||||
ty => ty,
|
ty => ty,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is an `impl Trait` or `dyn Trait`, returns that trait.
|
||||||
|
pub fn inherent_trait(&self) -> Option<Trait> {
|
||||||
|
match self {
|
||||||
|
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||||
|
predicates.iter().find_map(|pred| match pred {
|
||||||
|
GenericPredicate::Implemented(tr) => Some(tr.trait_),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for &Ty {
|
impl HirDisplay for &Ty {
|
||||||
|
@ -669,6 +736,28 @@ impl HirDisplay for Ty {
|
||||||
Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?,
|
Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?,
|
||||||
Ty::Param { name, .. } => write!(f, "{}", name)?,
|
Ty::Param { name, .. } => write!(f, "{}", name)?,
|
||||||
Ty::Bound(idx) => write!(f, "?{}", idx)?,
|
Ty::Bound(idx) => write!(f, "?{}", idx)?,
|
||||||
|
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||||
|
match self {
|
||||||
|
Ty::Dyn(_) => write!(f, "dyn ")?,
|
||||||
|
Ty::Opaque(_) => write!(f, "impl ")?,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
// looping by hand here just to format the bounds in a slightly nicer way
|
||||||
|
let mut first = true;
|
||||||
|
for p in predicates.iter() {
|
||||||
|
if !first {
|
||||||
|
write!(f, " + ")?;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
match p {
|
||||||
|
// don't show the $0 self type
|
||||||
|
GenericPredicate::Implemented(trait_ref) => {
|
||||||
|
trait_ref.hir_fmt_ext(f, false)?
|
||||||
|
}
|
||||||
|
GenericPredicate::Error => p.hir_fmt(f)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ty::Unknown => write!(f, "{{unknown}}")?,
|
Ty::Unknown => write!(f, "{{unknown}}")?,
|
||||||
Ty::Infer(..) => write!(f, "_")?,
|
Ty::Infer(..) => write!(f, "_")?,
|
||||||
}
|
}
|
||||||
|
@ -676,14 +765,16 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for TraitRef {
|
impl TraitRef {
|
||||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
fn hir_fmt_ext(
|
||||||
write!(
|
&self,
|
||||||
f,
|
f: &mut HirFormatter<impl HirDatabase>,
|
||||||
"{}: {}",
|
with_self_ty: bool,
|
||||||
self.substs[0].display(f.db),
|
) -> fmt::Result {
|
||||||
self.trait_.name(f.db).unwrap_or_else(Name::missing)
|
if with_self_ty {
|
||||||
)?;
|
write!(f, "{}: ", self.substs[0].display(f.db),)?;
|
||||||
|
}
|
||||||
|
write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
|
||||||
if self.substs.len() > 1 {
|
if self.substs.len() > 1 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(&self.substs[1..], ", ")?;
|
f.write_joined(&self.substs[1..], ", ")?;
|
||||||
|
@ -693,6 +784,28 @@ impl HirDisplay for TraitRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HirDisplay for TraitRef {
|
||||||
|
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||||
|
self.hir_fmt_ext(f, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HirDisplay for &GenericPredicate {
|
||||||
|
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||||
|
HirDisplay::hir_fmt(*self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HirDisplay for GenericPredicate {
|
||||||
|
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
|
||||||
|
GenericPredicate::Error => write!(f, "{{error}}")?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HirDisplay for Obligation {
|
impl HirDisplay for Obligation {
|
||||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
path::{GenericArg, PathSegment},
|
path::{GenericArg, PathSegment},
|
||||||
resolve::{Resolution, Resolver},
|
resolve::{Resolution, Resolver},
|
||||||
ty::AdtDef,
|
ty::AdtDef,
|
||||||
type_ref::TypeRef,
|
type_ref::{TypeBound, TypeRef},
|
||||||
BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct,
|
BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct,
|
||||||
StructField, Trait, TypeAlias, Union,
|
StructField, Trait, TypeAlias, Union,
|
||||||
};
|
};
|
||||||
|
@ -58,6 +58,22 @@ impl Ty {
|
||||||
let sig = Substs(inner_tys.into());
|
let sig = Substs(inner_tys.into());
|
||||||
Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
|
Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
|
||||||
}
|
}
|
||||||
|
TypeRef::DynTrait(bounds) => {
|
||||||
|
let self_ty = Ty::Bound(0);
|
||||||
|
let predicates = bounds
|
||||||
|
.iter()
|
||||||
|
.map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ty::Dyn(predicates.into())
|
||||||
|
}
|
||||||
|
TypeRef::ImplTrait(bounds) => {
|
||||||
|
let self_ty = Ty::Bound(0);
|
||||||
|
let predicates = bounds
|
||||||
|
.iter()
|
||||||
|
.map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ty::Opaque(predicates.into())
|
||||||
|
}
|
||||||
TypeRef::Error => Ty::Unknown,
|
TypeRef::Error => Ty::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,13 +326,46 @@ impl TraitRef {
|
||||||
TraitRef { trait_, substs }
|
TraitRef { trait_, substs }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn for_where_predicate(
|
pub(crate) fn from_where_predicate(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
pred: &WherePredicate,
|
pred: &WherePredicate,
|
||||||
) -> Option<TraitRef> {
|
) -> Option<TraitRef> {
|
||||||
let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
|
let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
|
||||||
TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty))
|
TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_type_bound(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
resolver: &Resolver,
|
||||||
|
bound: &TypeBound,
|
||||||
|
self_ty: Ty,
|
||||||
|
) -> Option<TraitRef> {
|
||||||
|
match bound {
|
||||||
|
TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)),
|
||||||
|
TypeBound::Error => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenericPredicate {
|
||||||
|
pub(crate) fn from_where_predicate(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
resolver: &Resolver,
|
||||||
|
where_predicate: &WherePredicate,
|
||||||
|
) -> GenericPredicate {
|
||||||
|
TraitRef::from_where_predicate(db, &resolver, where_predicate)
|
||||||
|
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_type_bound(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
resolver: &Resolver,
|
||||||
|
bound: &TypeBound,
|
||||||
|
self_ty: Ty,
|
||||||
|
) -> GenericPredicate {
|
||||||
|
TraitRef::from_type_bound(db, &resolver, bound, self_ty)
|
||||||
|
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,10 +425,7 @@ pub(crate) fn trait_env(
|
||||||
) -> Arc<super::TraitEnvironment> {
|
) -> Arc<super::TraitEnvironment> {
|
||||||
let predicates = resolver
|
let predicates = resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.map(|pred| {
|
.map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
|
||||||
TraitRef::for_where_predicate(db, &resolver, pred)
|
|
||||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Arc::new(super::TraitEnvironment { predicates })
|
Arc::new(super::TraitEnvironment { predicates })
|
||||||
|
@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query(
|
||||||
let resolver = def.resolver(db);
|
let resolver = def.resolver(db);
|
||||||
let predicates = resolver
|
let predicates = resolver
|
||||||
.where_predicates_in_scope()
|
.where_predicates_in_scope()
|
||||||
.map(|pred| {
|
.map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
|
||||||
TraitRef::for_where_predicate(db, &resolver, pred)
|
|
||||||
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
predicates.into()
|
predicates.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,12 +211,19 @@ fn iterate_trait_method_candidates<T>(
|
||||||
let krate = resolver.krate()?;
|
let krate = resolver.krate()?;
|
||||||
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
|
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
|
||||||
let env = lower::trait_env(db, resolver);
|
let env = lower::trait_env(db, resolver);
|
||||||
'traits: for t in resolver.traits_in_scope(db) {
|
// if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
|
||||||
|
let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db));
|
||||||
|
'traits: for t in traits {
|
||||||
let data = t.trait_data(db);
|
let data = t.trait_data(db);
|
||||||
|
|
||||||
|
// FIXME this is a bit of a hack, since Chalk should say the same thing
|
||||||
|
// anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
|
||||||
|
let inherently_implemented = ty.value.inherent_trait() == Some(t);
|
||||||
|
|
||||||
// we'll be lazy about checking whether the type implements the
|
// we'll be lazy about checking whether the type implements the
|
||||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||||
// iteration
|
// iteration
|
||||||
let mut known_implemented = false;
|
let mut known_implemented = inherently_implemented;
|
||||||
for item in data.items() {
|
for item in data.items() {
|
||||||
if let TraitItem::Function(m) = *item {
|
if let TraitItem::Function(m) = *item {
|
||||||
let data = m.data(db);
|
let data = m.data(db);
|
||||||
|
@ -271,6 +278,11 @@ pub(crate) fn implements_trait(
|
||||||
krate: Crate,
|
krate: Crate,
|
||||||
trait_: Trait,
|
trait_: Trait,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if ty.value.inherent_trait() == Some(trait_) {
|
||||||
|
// FIXME this is a bit of a hack, since Chalk should say the same thing
|
||||||
|
// anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
|
||||||
|
return true;
|
||||||
|
}
|
||||||
let env = lower::trait_env(db, resolver);
|
let env = lower::trait_env(db, resolver);
|
||||||
let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
|
let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
|
||||||
let solution = db.trait_solve(krate, goal);
|
let solution = db.trait_solve(krate, goal);
|
||||||
|
|
|
@ -3273,6 +3273,181 @@ fn test<T: ApplyL>(t: T) {
|
||||||
assert_eq!(t, "{unknown}");
|
assert_eq!(t, "{unknown}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impl_trait() {
|
||||||
|
assert_snapshot_matches!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait<T> {
|
||||||
|
fn foo(&self) -> T;
|
||||||
|
fn foo2(&self) -> i64;
|
||||||
|
}
|
||||||
|
fn bar() -> impl Trait<u64> {}
|
||||||
|
|
||||||
|
fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
|
||||||
|
x;
|
||||||
|
y;
|
||||||
|
let z = bar();
|
||||||
|
x.foo();
|
||||||
|
y.foo();
|
||||||
|
z.foo();
|
||||||
|
x.foo2();
|
||||||
|
y.foo2();
|
||||||
|
z.foo2();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
⋮
|
||||||
|
⋮[30; 34) 'self': &Self
|
||||||
|
⋮[55; 59) 'self': &Self
|
||||||
|
⋮[99; 101) '{}': ()
|
||||||
|
⋮[111; 112) 'x': impl Trait<u64>
|
||||||
|
⋮[131; 132) 'y': &impl Trait<u64>
|
||||||
|
⋮[152; 269) '{ ...2(); }': ()
|
||||||
|
⋮[158; 159) 'x': impl Trait<u64>
|
||||||
|
⋮[165; 166) 'y': &impl Trait<u64>
|
||||||
|
⋮[176; 177) 'z': impl Trait<u64>
|
||||||
|
⋮[180; 183) 'bar': fn bar() -> impl Trait<u64>
|
||||||
|
⋮[180; 185) 'bar()': impl Trait<u64>
|
||||||
|
⋮[191; 192) 'x': impl Trait<u64>
|
||||||
|
⋮[191; 198) 'x.foo()': {unknown}
|
||||||
|
⋮[204; 205) 'y': &impl Trait<u64>
|
||||||
|
⋮[204; 211) 'y.foo()': {unknown}
|
||||||
|
⋮[217; 218) 'z': impl Trait<u64>
|
||||||
|
⋮[217; 224) 'z.foo()': {unknown}
|
||||||
|
⋮[230; 231) 'x': impl Trait<u64>
|
||||||
|
⋮[230; 238) 'x.foo2()': i64
|
||||||
|
⋮[244; 245) 'y': &impl Trait<u64>
|
||||||
|
⋮[244; 252) 'y.foo2()': i64
|
||||||
|
⋮[258; 259) 'z': impl Trait<u64>
|
||||||
|
⋮[258; 266) 'z.foo2()': i64
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_trait() {
|
||||||
|
assert_snapshot_matches!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait<T> {
|
||||||
|
fn foo(&self) -> T;
|
||||||
|
fn foo2(&self) -> i64;
|
||||||
|
}
|
||||||
|
fn bar() -> dyn Trait<u64> {}
|
||||||
|
|
||||||
|
fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
|
||||||
|
x;
|
||||||
|
y;
|
||||||
|
let z = bar();
|
||||||
|
x.foo();
|
||||||
|
y.foo();
|
||||||
|
z.foo();
|
||||||
|
x.foo2();
|
||||||
|
y.foo2();
|
||||||
|
z.foo2();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
⋮
|
||||||
|
⋮[30; 34) 'self': &Self
|
||||||
|
⋮[55; 59) 'self': &Self
|
||||||
|
⋮[98; 100) '{}': ()
|
||||||
|
⋮[110; 111) 'x': dyn Trait<u64>
|
||||||
|
⋮[129; 130) 'y': &dyn Trait<u64>
|
||||||
|
⋮[149; 266) '{ ...2(); }': ()
|
||||||
|
⋮[155; 156) 'x': dyn Trait<u64>
|
||||||
|
⋮[162; 163) 'y': &dyn Trait<u64>
|
||||||
|
⋮[173; 174) 'z': dyn Trait<u64>
|
||||||
|
⋮[177; 180) 'bar': fn bar() -> dyn Trait<u64>
|
||||||
|
⋮[177; 182) 'bar()': dyn Trait<u64>
|
||||||
|
⋮[188; 189) 'x': dyn Trait<u64>
|
||||||
|
⋮[188; 195) 'x.foo()': {unknown}
|
||||||
|
⋮[201; 202) 'y': &dyn Trait<u64>
|
||||||
|
⋮[201; 208) 'y.foo()': {unknown}
|
||||||
|
⋮[214; 215) 'z': dyn Trait<u64>
|
||||||
|
⋮[214; 221) 'z.foo()': {unknown}
|
||||||
|
⋮[227; 228) 'x': dyn Trait<u64>
|
||||||
|
⋮[227; 235) 'x.foo2()': i64
|
||||||
|
⋮[241; 242) 'y': &dyn Trait<u64>
|
||||||
|
⋮[241; 249) 'y.foo2()': i64
|
||||||
|
⋮[255; 256) 'z': dyn Trait<u64>
|
||||||
|
⋮[255; 263) 'z.foo2()': i64
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_trait_bare() {
|
||||||
|
assert_snapshot_matches!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait {
|
||||||
|
fn foo(&self) -> u64;
|
||||||
|
}
|
||||||
|
fn bar() -> Trait {}
|
||||||
|
|
||||||
|
fn test(x: Trait, y: &Trait) -> u64 {
|
||||||
|
x;
|
||||||
|
y;
|
||||||
|
let z = bar();
|
||||||
|
x.foo();
|
||||||
|
y.foo();
|
||||||
|
z.foo();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
⋮
|
||||||
|
⋮[27; 31) 'self': &Self
|
||||||
|
⋮[61; 63) '{}': ()
|
||||||
|
⋮[73; 74) 'x': {unknown}
|
||||||
|
⋮[83; 84) 'y': &{unknown}
|
||||||
|
⋮[101; 176) '{ ...o(); }': ()
|
||||||
|
⋮[107; 108) 'x': {unknown}
|
||||||
|
⋮[114; 115) 'y': &{unknown}
|
||||||
|
⋮[125; 126) 'z': {unknown}
|
||||||
|
⋮[129; 132) 'bar': fn bar() -> {unknown}
|
||||||
|
⋮[129; 134) 'bar()': {unknown}
|
||||||
|
⋮[140; 141) 'x': {unknown}
|
||||||
|
⋮[140; 147) 'x.foo()': {unknown}
|
||||||
|
⋮[153; 154) 'y': &{unknown}
|
||||||
|
⋮[153; 160) 'y.foo()': {unknown}
|
||||||
|
⋮[166; 167) 'z': {unknown}
|
||||||
|
⋮[166; 173) 'z.foo()': {unknown}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn weird_bounds() {
|
||||||
|
assert_snapshot_matches!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait {}
|
||||||
|
fn test() {
|
||||||
|
let a: impl Trait + 'lifetime = foo;
|
||||||
|
let b: impl 'lifetime = foo;
|
||||||
|
let b: impl (Trait) = foo;
|
||||||
|
let b: impl ('lifetime) = foo;
|
||||||
|
let d: impl ?Sized = foo;
|
||||||
|
let e: impl Trait + ?Sized = foo;
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
⋮
|
||||||
|
⋮[26; 237) '{ ...foo; }': ()
|
||||||
|
⋮[36; 37) 'a': impl Trait + {error}
|
||||||
|
⋮[64; 67) 'foo': impl Trait + {error}
|
||||||
|
⋮[77; 78) 'b': impl {error}
|
||||||
|
⋮[97; 100) 'foo': impl {error}
|
||||||
|
⋮[110; 111) 'b': impl Trait
|
||||||
|
⋮[128; 131) 'foo': impl Trait
|
||||||
|
⋮[141; 142) 'b': impl {error}
|
||||||
|
⋮[163; 166) 'foo': impl {error}
|
||||||
|
⋮[176; 177) 'd': impl {error}
|
||||||
|
⋮[193; 196) 'foo': impl {error}
|
||||||
|
⋮[206; 207) 'e': impl Trait + {error}
|
||||||
|
⋮[231; 234) 'foo': impl Trait + {error}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||||
let file = db.parse(pos.file_id).ok().unwrap();
|
let file = db.parse(pos.file_id).ok().unwrap();
|
||||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||||
|
|
|
@ -80,7 +80,9 @@ impl ToChalk for Ty {
|
||||||
// FIXME this is clearly incorrect, but probably not too incorrect
|
// FIXME this is clearly incorrect, but probably not too incorrect
|
||||||
// and I'm not sure what to actually do with Ty::Unknown
|
// and I'm not sure what to actually do with Ty::Unknown
|
||||||
// maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
|
// maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
|
||||||
Ty::Unknown => {
|
//
|
||||||
|
// FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
|
||||||
|
Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
|
||||||
PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
|
PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! HIR for references to types. Paths in these are not yet resolved. They can
|
//! HIR for references to types. Paths in these are not yet resolved. They can
|
||||||
//! be directly created from an ast::TypeRef, without further queries.
|
//! be directly created from an ast::TypeRef, without further queries.
|
||||||
|
|
||||||
use ra_syntax::ast::{self, TypeAscriptionOwner};
|
use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner};
|
||||||
|
|
||||||
use crate::Path;
|
use crate::Path;
|
||||||
|
|
||||||
|
@ -49,8 +49,16 @@ pub enum TypeRef {
|
||||||
/// A fn pointer. Last element of the vector is the return type.
|
/// A fn pointer. Last element of the vector is the return type.
|
||||||
Fn(Vec<TypeRef>),
|
Fn(Vec<TypeRef>),
|
||||||
// For
|
// For
|
||||||
// ImplTrait,
|
ImplTrait(Vec<TypeBound>),
|
||||||
// DynTrait,
|
DynTrait(Vec<TypeBound>),
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub enum TypeBound {
|
||||||
|
Path(Path),
|
||||||
|
// also for<> bounds
|
||||||
|
// also Lifetimes
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +103,12 @@ impl TypeRef {
|
||||||
}
|
}
|
||||||
// for types are close enough for our purposes to the inner type for now...
|
// for types are close enough for our purposes to the inner type for now...
|
||||||
ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
|
ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
|
||||||
ast::TypeRef::ImplTraitType(_inner) => TypeRef::Error,
|
ast::TypeRef::ImplTraitType(inner) => {
|
||||||
ast::TypeRef::DynTraitType(_inner) => TypeRef::Error,
|
TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list()))
|
||||||
|
}
|
||||||
|
ast::TypeRef::DynTraitType(inner) => {
|
||||||
|
TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,3 +124,30 @@ impl TypeRef {
|
||||||
TypeRef::Tuple(Vec::new())
|
TypeRef::Tuple(Vec::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
|
||||||
|
if let Some(type_bounds) = type_bounds_opt {
|
||||||
|
type_bounds.bounds().map(TypeBound::from_ast).collect()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeBound {
|
||||||
|
pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
|
||||||
|
match node.kind() {
|
||||||
|
ast::TypeBoundKind::PathType(path_type) => {
|
||||||
|
let path = match path_type.path() {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return TypeBound::Error,
|
||||||
|
};
|
||||||
|
let path = match Path::from_ast(path) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return TypeBound::Error,
|
||||||
|
};
|
||||||
|
TypeBound::Path(path)
|
||||||
|
}
|
||||||
|
ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
env,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
@ -33,21 +34,13 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn discover(cargo_toml: &Path) -> Result<Sysroot> {
|
pub fn discover(cargo_toml: &Path) -> Result<Sysroot> {
|
||||||
let rustc_output = Command::new("rustc")
|
let src = try_find_src_path(cargo_toml)?;
|
||||||
.current_dir(cargo_toml.parent().unwrap())
|
|
||||||
.args(&["--print", "sysroot"])
|
|
||||||
.output()?;
|
|
||||||
if !rustc_output.status.success() {
|
|
||||||
Err("failed to locate sysroot")?
|
|
||||||
}
|
|
||||||
let stdout = String::from_utf8(rustc_output.stdout)?;
|
|
||||||
let sysroot_path = Path::new(stdout.trim());
|
|
||||||
let src = sysroot_path.join("lib/rustlib/src/rust/src");
|
|
||||||
if !src.exists() {
|
if !src.exists() {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"can't load standard library from sysroot\n\
|
"can't load standard library from sysroot\n\
|
||||||
{:?}\n\
|
{:?}\n\
|
||||||
try running `rustup component add rust-src`",
|
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
|
||||||
src,
|
src,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +76,23 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_find_src_path(cargo_toml: &Path) -> Result<PathBuf> {
|
||||||
|
if let Ok(path) = env::var("RUST_SRC_PATH") {
|
||||||
|
return Ok(path.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let rustc_output = Command::new("rustc")
|
||||||
|
.current_dir(cargo_toml.parent().unwrap())
|
||||||
|
.args(&["--print", "sysroot"])
|
||||||
|
.output()?;
|
||||||
|
if !rustc_output.status.success() {
|
||||||
|
Err("failed to locate sysroot")?;
|
||||||
|
}
|
||||||
|
let stdout = String::from_utf8(rustc_output.stdout)?;
|
||||||
|
let sysroot_path = Path::new(stdout.trim());
|
||||||
|
Ok(sysroot_path.join("lib/rustlib/src/rust/src"))
|
||||||
|
}
|
||||||
|
|
||||||
impl SysrootCrate {
|
impl SysrootCrate {
|
||||||
pub fn name(self, sysroot: &Sysroot) -> &str {
|
pub fn name(self, sysroot: &Sysroot) -> &str {
|
||||||
&sysroot.crates[self].name
|
&sysroot.crates[self].name
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp},
|
expr_extensions::{ArrayExprKind, BinOp, ElseBranch, LiteralKind, PrefixOp},
|
||||||
extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind},
|
extensions::{FieldKind, PathSegmentKind, SelfParamKind, StructKind, TypeBoundKind},
|
||||||
generated::*,
|
generated::*,
|
||||||
tokens::*,
|
tokens::*,
|
||||||
traits::*,
|
traits::*,
|
||||||
|
|
|
@ -382,7 +382,36 @@ impl ast::WherePred {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TypeBoundKind {
|
||||||
|
/// Trait
|
||||||
|
PathType(ast::PathType),
|
||||||
|
/// for<'a> ...
|
||||||
|
ForType(ast::ForType),
|
||||||
|
/// 'a
|
||||||
|
Lifetime(ast::SyntaxToken),
|
||||||
|
}
|
||||||
|
|
||||||
impl ast::TypeBound {
|
impl ast::TypeBound {
|
||||||
|
pub fn kind(&self) -> TypeBoundKind {
|
||||||
|
if let Some(path_type) = children(self).next() {
|
||||||
|
TypeBoundKind::PathType(path_type)
|
||||||
|
} else if let Some(for_type) = children(self).next() {
|
||||||
|
TypeBoundKind::ForType(for_type)
|
||||||
|
} else if let Some(lifetime) = self.lifetime() {
|
||||||
|
TypeBoundKind::Lifetime(lifetime)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lifetime(&self) -> Option<SyntaxToken> {
|
||||||
|
self.syntax()
|
||||||
|
.children_with_tokens()
|
||||||
|
.filter_map(|it| it.into_token())
|
||||||
|
.find(|it| it.kind() == LIFETIME)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn question_mark_token(&self) -> Option<SyntaxToken> {
|
pub fn question_mark_token(&self) -> Option<SyntaxToken> {
|
||||||
self.syntax()
|
self.syntax()
|
||||||
.children_with_tokens()
|
.children_with_tokens()
|
||||||
|
|
|
@ -78,6 +78,7 @@ See https://github.com/microsoft/vscode/issues/72308[microsoft/vscode#72308] for
|
||||||
(e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` )
|
(e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` )
|
||||||
* `rust-analyzer.trace.server`: enables internal logging
|
* `rust-analyzer.trace.server`: enables internal logging
|
||||||
* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging
|
* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging
|
||||||
|
* `RUST_SRC_PATH`: environment variable that overwrites the sysroot
|
||||||
|
|
||||||
|
|
||||||
## Emacs
|
## Emacs
|
||||||
|
|
Loading…
Reference in a new issue