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:
bors[bot] 2019-08-22 20:06:32 +00:00 committed by GitHub
commit 0c35d82329
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 471 additions and 55 deletions

View file

@ -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> {

View file

@ -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 {

View file

@ -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()
} }

View file

@ -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);

View file

@ -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();

View file

@ -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()
} }
} }

View file

@ -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,
}
}
}

View file

@ -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

View file

@ -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::*,

View file

@ -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()

View file

@ -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