From a324d066cb767876f9f3398f83db9f5a8dda8ce4 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 14:44:00 +0100 Subject: Rename Ty::Param => Ty::Placeholder This aligns more with Chalk. --- crates/ra_hir_ty/src/lib.rs | 10 +++++----- crates/ra_hir_ty/src/lower.rs | 8 ++++---- crates/ra_hir_ty/src/traits/chalk.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index c5fe18c85..69ad13952 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -291,7 +291,7 @@ pub enum Ty { /// {}` when we're type-checking the body of that function. In this /// situation, we know this stands for *some* type, but don't know the exact /// type. - Param(TypeParamId), + Placeholder(TypeParamId), /// A bound type variable. This is used in various places: when representing /// some polymorphic type like the type of function `fn f`, the type @@ -365,7 +365,7 @@ impl Substs { /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { - Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) + Substs(generic_params.iter().map(|(id, _)| Ty::Placeholder(id)).collect()) } /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). @@ -813,7 +813,7 @@ impl TypeWalk for Ty { p.walk(f); } } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} + Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self); } @@ -831,7 +831,7 @@ impl TypeWalk for Ty { p.walk_mut_binders(f, binders + 1); } } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} + Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self, binders); } @@ -1032,7 +1032,7 @@ impl HirDisplay for Ty { match self { Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, - Ty::Param(id) => { + Ty::Placeholder(id) => { let generics = generics(f.db, id.parent); let param_data = &generics.params.types[id.local_id]; match param_data.provenance { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index c68c5852b..df24c16a3 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -152,7 +152,7 @@ impl Ty { data.provenance == TypeParamProvenance::ArgumentImplTrait }) .nth(idx as usize) - .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); + .map_or(Ty::Unknown, |(id, _)| Ty::Placeholder(id)); param } else { Ty::Unknown @@ -270,7 +270,7 @@ impl Ty { let generics = generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Variable => { let idx = generics.param_idx(param_id).expect("matching generics"); Ty::Bound(idx) @@ -339,7 +339,7 @@ impl Ty { None => return Ty::Unknown, // this can't actually happen }; let param_id = match self_ty { - Ty::Param(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, + Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { let generics = generics(ctx.db, def); let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { @@ -544,7 +544,7 @@ impl GenericPredicate { let generics = generics(ctx.db, generic_def); let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => Ty::Param(param_id), + TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id), TypeParamLoweringMode::Variable => { let idx = generics.param_idx(param_id).expect("matching generics"); Ty::Bound(idx) diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 4974c565b..882160fa8 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -142,7 +142,7 @@ impl ToChalk for Ty { let substitution = proj_ty.parameters.to_chalk(db); chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() } - Ty::Param(id) => { + Ty::Placeholder(id) => { let interned_id = db.intern_type_param_id(id); PlaceholderIndex { ui: UniverseIndex::ROOT, @@ -184,7 +184,7 @@ impl ToChalk for Ty { let interned_id = crate::db::GlobalTypeParamId::from_intern_id( crate::salsa::InternId::from(idx.idx), ); - Ty::Param(db.lookup_intern_type_param_id(interned_id)) + Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) } chalk_ir::TyData::Alias(proj) => { let associated_ty = from_chalk(db, proj.associated_ty_id); -- cgit v1.2.3 From 5028b86cb8ed40d8b43ba2a1b1cd01377e363626 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 15:01:25 +0100 Subject: Move hir_fmt code to display module --- crates/ra_hir_ty/src/display.rs | 373 ++++++++++++++++++++++++++++++++++++++- crates/ra_hir_ty/src/lib.rs | 375 +--------------------------------------- 2 files changed, 376 insertions(+), 372 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index d1ff85f0f..14e089cf4 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs @@ -2,7 +2,12 @@ use std::fmt; -use crate::db::HirDatabase; +use crate::{ + db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate, + Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, +}; +use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup}; +use hir_expand::name::Name; pub struct HirFormatter<'a, 'b, DB> { pub db: &'a DB, @@ -97,3 +102,369 @@ where }) } } + +const TYPE_HINT_TRUNCATION: &str = "…"; + +impl HirDisplay for &Ty { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + HirDisplay::hir_fmt(*self, f) + } +} + +impl HirDisplay for ApplicationTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self.ctor { + TypeCtor::Bool => write!(f, "bool")?, + TypeCtor::Char => write!(f, "char")?, + TypeCtor::Int(t) => write!(f, "{}", t)?, + TypeCtor::Float(t) => write!(f, "{}", t)?, + TypeCtor::Str => write!(f, "str")?, + TypeCtor::Slice => { + let t = self.parameters.as_single(); + write!(f, "[{}]", t.display(f.db))?; + } + TypeCtor::Array => { + let t = self.parameters.as_single(); + write!(f, "[{}; _]", t.display(f.db))?; + } + TypeCtor::RawPtr(m) => { + let t = self.parameters.as_single(); + write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; + } + TypeCtor::Ref(m) => { + let t = self.parameters.as_single(); + let ty_display = if f.omit_verbose_types() { + t.display_truncated(f.db, f.max_size) + } else { + t.display(f.db) + }; + write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; + } + TypeCtor::Never => write!(f, "!")?, + TypeCtor::Tuple { .. } => { + let ts = &self.parameters; + if ts.len() == 1 { + write!(f, "({},)", ts[0].display(f.db))?; + } else { + write!(f, "(")?; + f.write_joined(&*ts.0, ", ")?; + write!(f, ")")?; + } + } + TypeCtor::FnPtr { .. } => { + let sig = FnSig::from_fn_ptr_substs(&self.parameters); + write!(f, "fn(")?; + f.write_joined(sig.params(), ", ")?; + write!(f, ") -> {}", sig.ret().display(f.db))?; + } + TypeCtor::FnDef(def) => { + let sig = f.db.callable_item_signature(def).subst(&self.parameters); + let name = match def { + CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), + CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), + CallableDef::EnumVariantId(e) => { + let enum_data = f.db.enum_data(e.parent); + enum_data.variants[e.local_id].name.clone() + } + }; + match def { + CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, + CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { + write!(f, "{}", name)? + } + } + if self.parameters.len() > 0 { + let generics = generics(f.db, def.into()); + let (parent_params, self_param, type_params, _impl_trait_params) = + generics.provenance_split(); + let total_len = parent_params + self_param + type_params; + // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? + if total_len > 0 { + write!(f, "<")?; + f.write_joined(&self.parameters.0[..total_len], ", ")?; + write!(f, ">")?; + } + } + write!(f, "(")?; + f.write_joined(sig.params(), ", ")?; + write!(f, ") -> {}", sig.ret().display(f.db))?; + } + TypeCtor::Adt(def_id) => { + let name = match def_id { + AdtId::StructId(it) => f.db.struct_data(it).name.clone(), + AdtId::UnionId(it) => f.db.union_data(it).name.clone(), + AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), + }; + write!(f, "{}", name)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + + let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); + let parameters_to_write = if f.omit_verbose_types() { + match self + .ctor + .as_generic_def() + .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) + .filter(|defaults| !defaults.is_empty()) + { + Option::None => self.parameters.0.as_ref(), + Option::Some(default_parameters) => { + for (i, parameter) in self.parameters.iter().enumerate() { + match (parameter, default_parameters.get(i)) { + (&Ty::Unknown, _) | (_, None) => { + non_default_parameters.push(parameter.clone()) + } + (_, Some(default_parameter)) + if parameter != default_parameter => + { + non_default_parameters.push(parameter.clone()) + } + _ => (), + } + } + &non_default_parameters + } + } + } else { + self.parameters.0.as_ref() + }; + + f.write_joined(parameters_to_write, ", ")?; + write!(f, ">")?; + } + } + TypeCtor::AssociatedType(type_alias) => { + let trait_ = match type_alias.lookup(f.db).container { + AssocContainerId::TraitId(it) => it, + _ => panic!("not an associated type"), + }; + let trait_name = f.db.trait_data(trait_).name.clone(); + let name = f.db.type_alias_data(type_alias).name.clone(); + write!(f, "{}::{}", trait_name, name)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + f.write_joined(&*self.parameters.0, ", ")?; + write!(f, ">")?; + } + } + TypeCtor::Closure { .. } => { + let sig = self.parameters[0] + .callable_sig(f.db) + .expect("first closure parameter should contain signature"); + let return_type_hint = sig.ret().display(f.db); + if sig.params().is_empty() { + write!(f, "|| -> {}", return_type_hint)?; + } else if f.omit_verbose_types() { + write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; + } else { + write!(f, "|")?; + f.write_joined(sig.params(), ", ")?; + write!(f, "| -> {}", return_type_hint)?; + }; + } + } + Ok(()) + } +} + +impl HirDisplay for ProjectionTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); + write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; + if self.parameters.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.parameters[1..], ", ")?; + write!(f, ">")?; + } + write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; + Ok(()) + } +} + +impl HirDisplay for Ty { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self { + Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, + Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, + Ty::Placeholder(id) => { + let generics = generics(f.db, id.parent); + let param_data = &generics.params.types[id.local_id]; + match param_data.provenance { + TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? + } + TypeParamProvenance::ArgumentImplTrait => { + write!(f, "impl ")?; + let bounds = f.db.generic_predicates_for_param(*id); + let substs = Substs::type_params_for_generics(&generics); + write_bounds_like_dyn_trait( + &bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), + f, + )?; + } + } + } + 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!(), + }; + write_bounds_like_dyn_trait(&predicates, f)?; + } + Ty::Unknown => write!(f, "{{unknown}}")?, + Ty::Infer(..) => write!(f, "_")?, + } + Ok(()) + } +} + +fn write_bounds_like_dyn_trait( + predicates: &[GenericPredicate], + f: &mut HirFormatter, +) -> fmt::Result { + // Note: This code is written to produce nice results (i.e. + // corresponding to surface Rust) for types that can occur in + // actual Rust. It will have weird results if the predicates + // aren't as expected (i.e. self types = $0, projection + // predicates for a certain trait come after the Implemented + // predicate for that trait). + let mut first = true; + let mut angle_open = false; + for p in predicates.iter() { + match p { + GenericPredicate::Implemented(trait_ref) => { + if angle_open { + write!(f, ">")?; + } + if !first { + write!(f, " + ")?; + } + // We assume that the self type is $0 (i.e. the + // existential) here, which is the only thing that's + // possible in actual Rust, and hence don't print it + write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; + if trait_ref.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&trait_ref.substs[1..], ", ")?; + // there might be assoc type bindings, so we leave the angle brackets open + angle_open = true; + } + } + GenericPredicate::Projection(projection_pred) => { + // in types in actual Rust, these will always come + // after the corresponding Implemented predicate + if angle_open { + write!(f, ", ")?; + } else { + write!(f, "<")?; + angle_open = true; + } + let name = + f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); + write!(f, "{} = ", name)?; + projection_pred.ty.hir_fmt(f)?; + } + GenericPredicate::Error => { + if angle_open { + // impl Trait + write!(f, ", ")?; + } else if !first { + // impl Trait + {error} + write!(f, " + ")?; + } + p.hir_fmt(f)?; + } + } + first = false; + } + if angle_open { + write!(f, ">")?; + } + Ok(()) +} + +impl TraitRef { + fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + self.substs[0].hir_fmt(f)?; + if use_as { + write!(f, " as ")?; + } else { + write!(f, ": ")?; + } + write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; + if self.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.substs[1..], ", ")?; + write!(f, ">")?; + } + Ok(()) + } +} + +impl HirDisplay for TraitRef { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + self.hir_fmt_ext(f, false) + } +} + +impl HirDisplay for &GenericPredicate { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + HirDisplay::hir_fmt(*self, f) + } +} + +impl HirDisplay for GenericPredicate { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + if f.should_truncate() { + return write!(f, "{}", TYPE_HINT_TRUNCATION); + } + + match self { + GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, + GenericPredicate::Projection(projection_pred) => { + write!(f, "<")?; + projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; + write!( + f, + ">::{} = {}", + f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, + projection_pred.ty.display(f.db) + )?; + } + GenericPredicate::Error => write!(f, "{{error}}")?, + } + Ok(()) + } +} + +impl HirDisplay for Obligation { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + match self { + Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), + Obligation::Projection(proj) => write!( + f, + "Normalize({} => {})", + proj.projection_ty.display(f.db), + proj.ty.display(f.db) + ), + } + } +} diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 69ad13952..571579cc4 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -41,13 +41,12 @@ mod marks; use std::ops::Deref; use std::sync::Arc; -use std::{fmt, iter, mem}; +use std::{iter, mem}; use hir_def::{ - expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId, - DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, + expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, + HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, }; -use hir_expand::name::Name; use ra_db::{impl_intern_key, salsa, CrateId}; use crate::{ @@ -55,7 +54,7 @@ use crate::{ primitive::{FloatTy, IntTy, Uncertain}, utils::{generics, make_mut_slice, Generics}, }; -use display::{HirDisplay, HirFormatter}; +use display::HirDisplay; pub use autoderef::autoderef; pub use infer::{do_infer_query, InferTy, InferenceResult}; @@ -836,369 +835,3 @@ impl TypeWalk for Ty { f(self, binders); } } - -const TYPE_HINT_TRUNCATION: &str = "…"; - -impl HirDisplay for &Ty { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - HirDisplay::hir_fmt(*self, f) - } -} - -impl HirDisplay for ApplicationTy { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self.ctor { - TypeCtor::Bool => write!(f, "bool")?, - TypeCtor::Char => write!(f, "char")?, - TypeCtor::Int(t) => write!(f, "{}", t)?, - TypeCtor::Float(t) => write!(f, "{}", t)?, - TypeCtor::Str => write!(f, "str")?, - TypeCtor::Slice => { - let t = self.parameters.as_single(); - write!(f, "[{}]", t.display(f.db))?; - } - TypeCtor::Array => { - let t = self.parameters.as_single(); - write!(f, "[{}; _]", t.display(f.db))?; - } - TypeCtor::RawPtr(m) => { - let t = self.parameters.as_single(); - write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; - } - TypeCtor::Ref(m) => { - let t = self.parameters.as_single(); - let ty_display = if f.omit_verbose_types() { - t.display_truncated(f.db, f.max_size) - } else { - t.display(f.db) - }; - write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?; - } - TypeCtor::Never => write!(f, "!")?, - TypeCtor::Tuple { .. } => { - let ts = &self.parameters; - if ts.len() == 1 { - write!(f, "({},)", ts[0].display(f.db))?; - } else { - write!(f, "(")?; - f.write_joined(&*ts.0, ", ")?; - write!(f, ")")?; - } - } - TypeCtor::FnPtr { .. } => { - let sig = FnSig::from_fn_ptr_substs(&self.parameters); - write!(f, "fn(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ") -> {}", sig.ret().display(f.db))?; - } - TypeCtor::FnDef(def) => { - let sig = f.db.callable_item_signature(def).subst(&self.parameters); - let name = match def { - CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), - CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), - CallableDef::EnumVariantId(e) => { - let enum_data = f.db.enum_data(e.parent); - enum_data.variants[e.local_id].name.clone() - } - }; - match def { - CallableDef::FunctionId(_) => write!(f, "fn {}", name)?, - CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { - write!(f, "{}", name)? - } - } - if self.parameters.len() > 0 { - let generics = generics(f.db, def.into()); - let (parent_params, self_param, type_params, _impl_trait_params) = - generics.provenance_split(); - let total_len = parent_params + self_param + type_params; - // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? - if total_len > 0 { - write!(f, "<")?; - f.write_joined(&self.parameters.0[..total_len], ", ")?; - write!(f, ">")?; - } - } - write!(f, "(")?; - f.write_joined(sig.params(), ", ")?; - write!(f, ") -> {}", sig.ret().display(f.db))?; - } - TypeCtor::Adt(def_id) => { - let name = match def_id { - AdtId::StructId(it) => f.db.struct_data(it).name.clone(), - AdtId::UnionId(it) => f.db.union_data(it).name.clone(), - AdtId::EnumId(it) => f.db.enum_data(it).name.clone(), - }; - write!(f, "{}", name)?; - if self.parameters.len() > 0 { - write!(f, "<")?; - - let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); - let parameters_to_write = if f.omit_verbose_types() { - match self - .ctor - .as_generic_def() - .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) - .filter(|defaults| !defaults.is_empty()) - { - Option::None => self.parameters.0.as_ref(), - Option::Some(default_parameters) => { - for (i, parameter) in self.parameters.iter().enumerate() { - match (parameter, default_parameters.get(i)) { - (&Ty::Unknown, _) | (_, None) => { - non_default_parameters.push(parameter.clone()) - } - (_, Some(default_parameter)) - if parameter != default_parameter => - { - non_default_parameters.push(parameter.clone()) - } - _ => (), - } - } - &non_default_parameters - } - } - } else { - self.parameters.0.as_ref() - }; - - f.write_joined(parameters_to_write, ", ")?; - write!(f, ">")?; - } - } - TypeCtor::AssociatedType(type_alias) => { - let trait_ = match type_alias.lookup(f.db).container { - AssocContainerId::TraitId(it) => it, - _ => panic!("not an associated type"), - }; - let trait_name = f.db.trait_data(trait_).name.clone(); - let name = f.db.type_alias_data(type_alias).name.clone(); - write!(f, "{}::{}", trait_name, name)?; - if self.parameters.len() > 0 { - write!(f, "<")?; - f.write_joined(&*self.parameters.0, ", ")?; - write!(f, ">")?; - } - } - TypeCtor::Closure { .. } => { - let sig = self.parameters[0] - .callable_sig(f.db) - .expect("first closure parameter should contain signature"); - let return_type_hint = sig.ret().display(f.db); - if sig.params().is_empty() { - write!(f, "|| -> {}", return_type_hint)?; - } else if f.omit_verbose_types() { - write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?; - } else { - write!(f, "|")?; - f.write_joined(sig.params(), ", ")?; - write!(f, "| -> {}", return_type_hint)?; - }; - } - } - Ok(()) - } -} - -impl HirDisplay for ProjectionTy { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); - write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; - if self.parameters.len() > 1 { - write!(f, "<")?; - f.write_joined(&self.parameters[1..], ", ")?; - write!(f, ">")?; - } - write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?; - Ok(()) - } -} - -impl HirDisplay for Ty { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self { - Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, - Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, - Ty::Placeholder(id) => { - let generics = generics(f.db, id.parent); - let param_data = &generics.params.types[id.local_id]; - match param_data.provenance { - TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? - } - TypeParamProvenance::ArgumentImplTrait => { - write!(f, "impl ")?; - let bounds = f.db.generic_predicates_for_param(*id); - let substs = Substs::type_params_for_generics(&generics); - write_bounds_like_dyn_trait( - &bounds.iter().map(|b| b.clone().subst(&substs)).collect::>(), - f, - )?; - } - } - } - 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!(), - }; - write_bounds_like_dyn_trait(&predicates, f)?; - } - Ty::Unknown => write!(f, "{{unknown}}")?, - Ty::Infer(..) => write!(f, "_")?, - } - Ok(()) - } -} - -fn write_bounds_like_dyn_trait( - predicates: &[GenericPredicate], - f: &mut HirFormatter, -) -> fmt::Result { - // Note: This code is written to produce nice results (i.e. - // corresponding to surface Rust) for types that can occur in - // actual Rust. It will have weird results if the predicates - // aren't as expected (i.e. self types = $0, projection - // predicates for a certain trait come after the Implemented - // predicate for that trait). - let mut first = true; - let mut angle_open = false; - for p in predicates.iter() { - match p { - GenericPredicate::Implemented(trait_ref) => { - if angle_open { - write!(f, ">")?; - } - if !first { - write!(f, " + ")?; - } - // We assume that the self type is $0 (i.e. the - // existential) here, which is the only thing that's - // possible in actual Rust, and hence don't print it - write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; - if trait_ref.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&trait_ref.substs[1..], ", ")?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; - } - } - GenericPredicate::Projection(projection_pred) => { - // in types in actual Rust, these will always come - // after the corresponding Implemented predicate - if angle_open { - write!(f, ", ")?; - } else { - write!(f, "<")?; - angle_open = true; - } - let name = - f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); - write!(f, "{} = ", name)?; - projection_pred.ty.hir_fmt(f)?; - } - GenericPredicate::Error => { - if angle_open { - // impl Trait - write!(f, ", ")?; - } else if !first { - // impl Trait + {error} - write!(f, " + ")?; - } - p.hir_fmt(f)?; - } - } - first = false; - } - if angle_open { - write!(f, ">")?; - } - Ok(()) -} - -impl TraitRef { - fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - self.substs[0].hir_fmt(f)?; - if use_as { - write!(f, " as ")?; - } else { - write!(f, ": ")?; - } - write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; - if self.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&self.substs[1..], ", ")?; - write!(f, ">")?; - } - Ok(()) - } -} - -impl HirDisplay for TraitRef { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - self.hir_fmt_ext(f, false) - } -} - -impl HirDisplay for &GenericPredicate { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - HirDisplay::hir_fmt(*self, f) - } -} - -impl HirDisplay for GenericPredicate { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - if f.should_truncate() { - return write!(f, "{}", TYPE_HINT_TRUNCATION); - } - - match self { - GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, - GenericPredicate::Projection(projection_pred) => { - write!(f, "<")?; - projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; - write!( - f, - ">::{} = {}", - f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name, - projection_pred.ty.display(f.db) - )?; - } - GenericPredicate::Error => write!(f, "{{error}}")?, - } - Ok(()) - } -} - -impl HirDisplay for Obligation { - fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { - match self { - Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), - Obligation::Projection(proj) => write!( - f, - "Normalize({} => {})", - proj.projection_ty.display(f.db), - proj.ty.display(f.db) - ), - } - } -} -- cgit v1.2.3 From 0bfebb8b2042e787c16bbfa26b1cbcd9425de2ab Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 14 Feb 2020 19:33:39 +0100 Subject: Make AtomicX type resolve again --- crates/ra_project_model/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fef405b7f..250255813 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -418,8 +418,10 @@ pub fn get_rustc_cfg_options() -> CfgOptions { // Some nightly-only cfgs, which are required for stdlib { cfg_options.insert_atom("target_thread_local".into()); - for &target_has_atomic in ["16", "32", "64", "8", "cas", "ptr"].iter() { - cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into()) + for &target_has_atomic in ["8", "16", "32", "64", "cas", "ptr"].iter() { + cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into()); + cfg_options + .insert_key_value("target_has_atomic_load_store".into(), target_has_atomic.into()); } } -- cgit v1.2.3 From 001dd6a2000ce4adada0ab6e4ed8fd67cb8eb569 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 19:16:42 +0100 Subject: Make Self implement the trait inside trait default methods --- crates/ra_hir_def/src/resolver.rs | 6 +---- crates/ra_hir_ty/src/lower.rs | 32 +++++++++++++++++++++--- crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 48 ++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 05cf4646a..e2b228e80 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -542,11 +542,7 @@ impl Resolver { fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { let params = db.generic_params(def); - if params.types.is_empty() { - self - } else { - self.push_scope(Scope::GenericParams { def, params }) - } + self.push_scope(Scope::GenericParams { def, params }) } fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver { diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index df24c16a3..6a2aded02 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -14,9 +14,9 @@ use hir_def::{ path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, - LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, - VariantId, + AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, + ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, + UnionId, VariantId, }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -672,11 +672,35 @@ impl TraitEnvironment { pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc { let ctx = TyLoweringContext::new(db, &resolver) .with_type_param_mode(TypeParamLoweringMode::Placeholder); - let predicates = resolver + let mut predicates = resolver .where_predicates_in_scope() .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) .collect::>(); + if let Some(def) = resolver.generic_def() { + let container: Option = match def { + // FIXME: is there a function for this? + GenericDefId::FunctionId(f) => Some(f.lookup(db).container), + GenericDefId::AdtId(_) => None, + GenericDefId::TraitId(_) => None, + GenericDefId::TypeAliasId(t) => Some(t.lookup(db).container), + GenericDefId::ImplId(_) => None, + GenericDefId::EnumVariantId(_) => None, + GenericDefId::ConstId(c) => Some(c.lookup(db).container), + }; + if let Some(AssocContainerId::TraitId(trait_id)) = container { + // add `Self: Trait` to the environment in trait + // function default implementations (and hypothetical code + // inside consts or type aliases) + test_utils::tested_by!(trait_self_implements_self); + let substs = Substs::type_params(db, trait_id); + let trait_ref = TraitRef { trait_: trait_id, substs }; + let pred = GenericPredicate::Implemented(trait_ref); + + predicates.push(pred); + } + } + Arc::new(TraitEnvironment { predicates }) } } diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..ae47855e9 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -6,4 +6,5 @@ test_utils::marks!( type_var_resolves_to_int_var match_ergonomics_ref coerce_merge_fail_fallback + trait_self_implements_self ); diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 17611ddbf..aa2018944 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -299,6 +299,54 @@ fn test() { ); } +#[test] +fn trait_default_method_self_bound_implements_trait() { + test_utils::covers!(trait_self_implements_self); + assert_snapshot!( + infer(r#" +trait Trait { + fn foo(&self) -> i64; + fn bar(&self) -> { + let x = self.foo(); + } +} +"#), + @r###" + [27; 31) 'self': &Self + [53; 57) 'self': &Self + [62; 97) '{ ... }': () + [76; 77) 'x': i64 + [80; 84) 'self': &Self + [80; 90) 'self.foo()': i64 + "### + ); +} + +#[test] +fn trait_default_method_self_bound_implements_super_trait() { + test_utils::covers!(trait_self_implements_self); + assert_snapshot!( + infer(r#" +trait SuperTrait { + fn foo(&self) -> i64; +} +trait Trait: SuperTrait { + fn bar(&self) -> { + let x = self.foo(); + } +} +"#), + @r###" + [32; 36) 'self': &Self + [86; 90) 'self': &Self + [95; 130) '{ ... }': () + [109; 110) 'x': i64 + [113; 117) 'self': &Self + [113; 123) 'self.foo()': i64 + "### + ); +} + #[test] fn infer_project_associated_type() { // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 -- cgit v1.2.3 From f47dc4de8d7aadea17dba023ece70e5b170274b1 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 14 Feb 2020 21:08:25 +0100 Subject: Check that impl self type matches up with expected self type in path mode Fixes #3144. --- crates/ra_hir_ty/src/marks.rs | 1 + crates/ra_hir_ty/src/method_resolution.rs | 9 +++++++ crates/ra_hir_ty/src/tests/method_resolution.rs | 32 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs index 0f754eb9c..4e0828425 100644 --- a/crates/ra_hir_ty/src/marks.rs +++ b/crates/ra_hir_ty/src/marks.rs @@ -4,6 +4,7 @@ test_utils::marks!( type_var_cycles_resolve_completely type_var_cycles_resolve_as_possible type_var_resolves_to_int_var + impl_self_type_match_without_receiver match_ergonomics_ref coerce_merge_fail_fallback ); diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 5283bff28..4f8c52433 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -425,6 +425,15 @@ fn iterate_inherent_methods( if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { continue; } + // we have to check whether the self type unifies with the type + // that the impl is for. If we have a receiver type, this + // already happens in `is_valid_candidate` above; if not, we + // check it here + if receiver_ty.is_none() && inherent_impl_substs(db, impl_block, self_ty).is_none() + { + test_utils::tested_by!(impl_self_type_match_without_receiver); + continue; + } if let Some(result) = callback(&self_ty.value, item) { return Some(result); } diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 1722563aa..1f767d324 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -963,6 +963,38 @@ fn test() { S2.into()<|>; } assert_eq!(t, "{unknown}"); } +#[test] +fn method_resolution_overloaded_method() { + test_utils::covers!(impl_self_type_match_without_receiver); + let t = type_at( + r#" +//- main.rs +struct Wrapper(T); +struct Foo(T); +struct Bar(T); + +impl Wrapper> { + pub fn new(foo_: T) -> Self { + Wrapper(Foo(foo_)) + } +} + +impl Wrapper> { + pub fn new(bar_: T) -> Self { + Wrapper(Bar(bar_)) + } +} + +fn main() { + let a = Wrapper::>::new(1.0); + let b = Wrapper::>::new(1.0); + (a, b)<|>; +} +"#, + ); + assert_eq!(t, "(Wrapper>, Wrapper>)") +} + #[test] fn method_resolution_encountering_fn_type() { type_at( -- cgit v1.2.3 From 843f03a3d2d242b765dc2b972d7d29ea85ec881e Mon Sep 17 00:00:00 2001 From: Benjamin Brittain Date: Fri, 14 Feb 2020 16:15:27 -0500 Subject: Bump crate resolution limit for large projects Change-Id: Ie0221e5bcfd1779cd5e241f96b4489e5bd3854c1 --- crates/ra_hir_def/src/nameres/collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 6352c71ef..b1f3f525d 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -146,7 +146,7 @@ where ReachedFixedPoint::Yes => break, ReachedFixedPoint::No => i += 1, } - if i == 1000 { + if i == 10000 { log::error!("name resolution is stuck"); break; } -- cgit v1.2.3 From 3484d727c3b26e9596ec3bd671e2a76a87cdb5fd Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 15 Feb 2020 18:00:14 +0100 Subject: Extend analysis-stats a bit This adds some tools helpful when debugging nondeterminism in analysis-stats: - a `--randomize` option that analyses everything in random order - a `-vv` option that prints even more detail Also add a debug log if Chalk fuel is exhausted (which would be a source of nondeterminism, but didn't happen in my tests). I found one source of nondeterminism (rust-lang/chalk#331), but there are still other cases remaining. --- crates/ra_cli/Cargo.toml | 2 + crates/ra_cli/src/analysis_stats.rs | 83 +++++++++++++++++++++++++++++++++---- crates/ra_cli/src/main.rs | 22 +++++++--- crates/ra_hir_ty/src/traits.rs | 3 ++ 4 files changed, 96 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index bcd408421..53d4876f6 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml @@ -6,8 +6,10 @@ authors = ["rust-analyzer developers"] publish = false [dependencies] +itertools = "0.8.0" pico-args = "0.3.0" env_logger = { version = "0.7.1", default-features = false } +rand = { version = "0.7.0", features = ["small_rng"] } ra_syntax = { path = "../ra_syntax" } ra_ide = { path = "../ra_ide" } diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 833235bff..6d2dd34c6 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs @@ -2,6 +2,9 @@ use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; +use itertools::Itertools; +use rand::{seq::SliceRandom, thread_rng}; + use hir::{ db::{DefDatabase, HirDatabase}, AssocItem, Crate, HasSource, HirDisplay, ModuleDef, @@ -19,6 +22,7 @@ pub fn run( path: &Path, only: Option<&str>, with_deps: bool, + randomize: bool, ) -> Result<()> { let db_load_time = Instant::now(); let (mut host, roots) = ra_batch::load_cargo(path)?; @@ -41,7 +45,11 @@ pub fn run( }) .collect::>(); - for krate in Crate::all(db) { + let mut krates = Crate::all(db); + if randomize { + krates.shuffle(&mut thread_rng()); + } + for krate in krates { let module = krate.root_module(db).expect("crate without root module"); let file_id = module.definition_source(db).file_id; if members.contains(&db.file_source_root(file_id.original_file(db))) { @@ -50,6 +58,10 @@ pub fn run( } } + if randomize { + visit_queue.shuffle(&mut thread_rng()); + } + println!("Crates in this dir: {}", num_crates); let mut num_decls = 0; let mut funcs = Vec::new(); @@ -79,10 +91,14 @@ pub fn run( println!("Total functions: {}", funcs.len()); println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); + if randomize { + funcs.shuffle(&mut thread_rng()); + } + let inference_time = Instant::now(); let mut bar = match verbosity { - Verbosity::Verbose | Verbosity::Normal => ProgressReport::new(funcs.len() as u64), - Verbosity::Quiet => ProgressReport::hidden(), + Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), + _ => ProgressReport::new(funcs.len() as u64), }; bar.tick(); @@ -92,7 +108,20 @@ pub fn run( let mut num_type_mismatches = 0; for f in funcs { let name = f.name(db); - let mut msg = format!("processing: {}", name); + let full_name = f + .module(db) + .path_to_root(db) + .into_iter() + .rev() + .filter_map(|it| it.name(db)) + .chain(Some(f.name(db))) + .join("::"); + if let Some(only_name) = only { + if name.to_string() != only_name && full_name != only_name { + continue; + } + } + let mut msg = format!("processing: {}", full_name); if verbosity.is_verbose() { let src = f.source(db); let original_file = src.file_id.original_file(db); @@ -100,15 +129,15 @@ pub fn run( let syntax_range = src.value.syntax().text_range(); write!(msg, " ({:?} {})", path, syntax_range).unwrap(); } - bar.set_message(&msg); - if let Some(only_name) = only { - if name.to_string() != only_name { - continue; - } + if verbosity.is_spammy() { + bar.println(format!("{}", msg)); } + bar.set_message(&msg); let f_id = FunctionId::from(f); let body = db.body(f_id.into()); let inference_result = db.infer(f_id.into()); + let (previous_exprs, previous_unknown, previous_partially_unknown) = + (num_exprs, num_exprs_unknown, num_exprs_partially_unknown); for (expr_id, _) in body.exprs.iter() { let ty = &inference_result[expr_id]; num_exprs += 1; @@ -125,6 +154,33 @@ pub fn run( num_exprs_partially_unknown += 1; } } + if only.is_some() && verbosity.is_spammy() { + // in super-verbose mode for just one function, we print every single expression + let (_, sm) = db.body_with_source_map(f_id.into()); + let src = sm.expr_syntax(expr_id); + if let Some(src) = src { + let original_file = src.file_id.original_file(db); + let line_index = host.analysis().file_line_index(original_file).unwrap(); + let text_range = src.value.either( + |it| it.syntax_node_ptr().range(), + |it| it.syntax_node_ptr().range(), + ); + let (start, end) = ( + line_index.line_col(text_range.start()), + line_index.line_col(text_range.end()), + ); + bar.println(format!( + "{}:{}-{}:{}: {}", + start.line + 1, + start.col_utf16, + end.line + 1, + end.col_utf16, + ty.display(db) + )); + } else { + bar.println(format!("unknown location: {}", ty.display(db))); + } + } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { num_type_mismatches += 1; if verbosity.is_verbose() { @@ -164,6 +220,15 @@ pub fn run( } } } + if verbosity.is_spammy() { + bar.println(format!( + "In {}: {} exprs, {} unknown, {} partial", + full_name, + num_exprs - previous_exprs, + num_exprs_unknown - previous_unknown, + num_exprs_partially_unknown - previous_partially_unknown + )); + } bar.inc(1); } bar.finish_and_clear(); diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 806612c2c..6a0e447b9 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs @@ -16,6 +16,7 @@ type Result = std::result::Result>; #[derive(Clone, Copy)] pub enum Verbosity { + Spammy, Verbose, Normal, Quiet, @@ -24,7 +25,13 @@ pub enum Verbosity { impl Verbosity { fn is_verbose(self) -> bool { match self { - Verbosity::Verbose => true, + Verbosity::Verbose | Verbosity::Spammy => true, + _ => false, + } + } + fn is_spammy(self) -> bool { + match self { + Verbosity::Spammy => true, _ => false, } } @@ -86,14 +93,18 @@ fn main() -> Result<()> { return Ok(()); } let verbosity = match ( + matches.contains(["-vv", "--spammy"]), matches.contains(["-v", "--verbose"]), matches.contains(["-q", "--quiet"]), ) { - (false, false) => Verbosity::Normal, - (false, true) => Verbosity::Quiet, - (true, false) => Verbosity::Verbose, - (true, true) => Err("Invalid flags: -q conflicts with -v")?, + (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?, + (true, _, false) => Verbosity::Spammy, + (false, false, false) => Verbosity::Normal, + (false, false, true) => Verbosity::Quiet, + (false, true, false) => Verbosity::Verbose, + (false, true, true) => Err("Invalid flags: -q conflicts with -v")?, }; + let randomize = matches.contains("--randomize"); let memory_usage = matches.contains("--memory-usage"); let only: Option = matches.opt_value_from_str(["-o", "--only"])?; let with_deps: bool = matches.contains("--with-deps"); @@ -111,6 +122,7 @@ fn main() -> Result<()> { path.as_ref(), only.as_ref().map(String::as_ref), with_deps, + randomize, )?; } "analysis-bench" => { diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 88af61e87..ff8e75b48 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs @@ -60,6 +60,9 @@ impl TraitSolver { context.0.db.check_canceled(); let remaining = fuel.get(); fuel.set(remaining - 1); + if remaining == 0 { + log::debug!("fuel exhausted"); + } remaining > 0 }) } -- cgit v1.2.3 From 11dda319413a7c08dc47a2949e20e1ad1f901d5b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 15 Feb 2020 23:23:44 +0100 Subject: Remove extra dep --- crates/ra_ide_db/Cargo.toml | 1 - 1 file changed, 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index 716e88bc1..495fffb5a 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml @@ -22,7 +22,6 @@ fst = { version = "0.3.1", default-features = false } rustc-hash = "1.0" unicase = "2.2.0" superslice = "1.0.0" -rand = { version = "0.7.0", features = ["small_rng"] } once_cell = "1.2.0" ra_syntax = { path = "../ra_syntax" } -- cgit v1.2.3 From e14e7ffa34bf9a458681fe7490ac2d51b02ff908 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 16 Feb 2020 12:57:19 +0100 Subject: Fix coercion of &T to itself The autoderef coercion logic did not handle matching placeholders. This led to some type mismatches. --- crates/ra_hir_ty/src/infer/unify.rs | 2 ++ crates/ra_hir_ty/src/tests/coercion.rs | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index fe05642ae..1dc842f40 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs @@ -249,6 +249,8 @@ impl InferenceTable { match (ty1, ty2) { (Ty::Unknown, _) | (_, Ty::Unknown) => true, + (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true, + (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index fc5ef36a5..42330b269 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -526,3 +526,25 @@ fn test() { "### ); } + +#[test] +fn coerce_placeholder_ref() { + // placeholders should unify, even behind references + assert_snapshot!( + infer_with_mismatches(r#" +struct S { t: T } +impl S { + fn get(&self) -> &TT { + &self.t + } +} +"#, true), + @r###" + [51; 55) 'self': &S + [64; 87) '{ ... }': &TT + [74; 81) '&self.t': &TT + [75; 79) 'self': &S + [75; 81) 'self.t': TT + "### + ); +} -- cgit v1.2.3 From 28fa5edbcead160d01932d49573bc60d8d80602c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 16 Feb 2020 17:06:01 +0100 Subject: Add module colors to css --- crates/ra_ide/src/snapshots/highlighting.html | 1 + crates/ra_ide/src/snapshots/rainbow_highlighting.html | 1 + crates/ra_ide/src/syntax_highlighting.rs | 1 + 3 files changed, 3 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 1cc55e78b..a02dbaf2f 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .literal { color: #BFEBBF; } .literal\.numeric { color: #6A8759; } .macro { color: #94BFF3; } +.module { color: #AFD8AF; } .variable { color: #DCDCCC; } .variable\.mut { color: #DCDCCC; text-decoration: underline; } diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 918fd4b97..95f038f00 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html @@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .literal { color: #BFEBBF; } .literal\.numeric { color: #6A8759; } .macro { color: #94BFF3; } +.module { color: #AFD8AF; } .variable { color: #DCDCCC; } .variable\.mut { color: #DCDCCC; text-decoration: underline; } diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 174e13595..20c414ca1 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -365,6 +365,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .literal { color: #BFEBBF; } .literal\\.numeric { color: #6A8759; } .macro { color: #94BFF3; } +.module { color: #AFD8AF; } .variable { color: #DCDCCC; } .variable\\.mut { color: #DCDCCC; text-decoration: underline; } -- cgit v1.2.3 From 98cc51580d0b8a6662f0155d8a45a8cfff469d72 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 16 Feb 2020 18:04:08 +0100 Subject: Enable profiling for bench --- crates/ra_cli/src/analysis_bench.rs | 2 ++ crates/ra_lsp_server/src/main.rs | 7 +------ crates/ra_prof/src/lib.rs | 7 +++++++ 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'crates') diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs index 5485a38ff..764df6b9e 100644 --- a/crates/ra_cli/src/analysis_bench.rs +++ b/crates/ra_cli/src/analysis_bench.rs @@ -20,6 +20,8 @@ pub(crate) enum Op { } pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { + ra_prof::init(); + let start = Instant::now(); eprint!("loading: "); let (mut host, roots) = ra_batch::load_cargo(path)?; diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index c8a017c5c..ed2eaabd4 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs @@ -15,13 +15,8 @@ fn main() -> Result<()> { fn setup_logging() -> Result<()> { std::env::set_var("RUST_BACKTRACE", "short"); - env_logger::try_init()?; - - ra_prof::set_filter(match std::env::var("RA_PROFILE") { - Ok(spec) => ra_prof::Filter::from_spec(&spec), - Err(_) => ra_prof::Filter::disabled(), - }); + ra_prof::init(); Ok(()) } diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index d38ff397e..c0bfbc2ee 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs @@ -26,6 +26,13 @@ pub use crate::memory_usage::{Bytes, MemoryUsage}; #[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; +pub fn init() { + set_filter(match std::env::var("RA_PROFILE") { + Ok(spec) => Filter::from_spec(&spec), + Err(_) => Filter::disabled(), + }); +} + /// Set profiling filter. It specifies descriptions allowed to profile. /// This is helpful when call stack has too many nested profiling scopes. /// Additionally filter can specify maximum depth of profiling scopes nesting. -- cgit v1.2.3