summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/adt.rs244
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs362
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs217
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs75
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs108
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs43
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs64
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs114
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs102
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs235
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs110
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs159
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs101
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml6
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/from_id.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs158
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs4
67 files changed, 2130 insertions, 889 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index e8cff2f3e..4ad8e7597 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -15,17 +15,17 @@ arrayvec = "0.7.2"
bitflags = "1.3.2"
cov-mark = "2.0.0-pre.1"
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
-dashmap = { version = "=5.3.4", features = ["raw-api"] }
+dashmap = { version = "=5.4.0", features = ["raw-api"] }
drop_bomb = "0.1.5"
either = "1.7.0"
fst = { version = "0.4.7", default-features = false }
hashbrown = { version = "0.12.1", default-features = false }
indexmap = "1.9.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.12.0"
+once_cell = "1.15.0"
rustc-hash = "1.1.0"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
tracing = "0.1.35"
stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
index 277135d6d..938db032f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/adt.rs
@@ -1,12 +1,12 @@
//! Defines hir-level representation of structs, enums and unions
-use std::sync::Arc;
+use std::{num::NonZeroU32, sync::Arc};
use base_db::CrateId;
use either::Either;
use hir_expand::{
name::{AsName, Name},
- InFile,
+ HirFileId, InFile,
};
use la_arena::{Arena, ArenaMap};
use syntax::ast::{self, HasName, HasVisibility};
@@ -14,15 +14,18 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
use crate::{
body::{CfgExpander, LowerCtx},
+ builtin_type::{BuiltinInt, BuiltinUint},
db::DefDatabase,
intern::Interned,
- item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
+ item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
+ nameres::diagnostics::DefDiagnostic,
src::HasChildSource,
src::HasSource,
trace::Trace,
type_ref::TypeRef,
visibility::RawVisibility,
- EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
+ EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
+ VariantId,
};
use cfg::CfgOptions;
@@ -31,7 +34,7 @@ use cfg::CfgOptions;
pub struct StructData {
pub name: Name,
pub variant_data: Arc<VariantData>,
- pub repr: Option<ReprKind>,
+ pub repr: Option<ReprData>,
pub visibility: RawVisibility,
}
@@ -39,6 +42,7 @@ pub struct StructData {
pub struct EnumData {
pub name: Name,
pub variants: Arena<EnumVariantData>,
+ pub repr: Option<ReprData>,
pub visibility: RawVisibility,
}
@@ -63,10 +67,19 @@ pub struct FieldData {
pub visibility: RawVisibility,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum ReprKind {
- Packed,
- Other,
+ C,
+ BuiltinInt { builtin: Either<BuiltinInt, BuiltinUint>, is_c: bool },
+ Transparent,
+ Default,
+}
+
+#[derive(Copy, Debug, Clone, PartialEq, Eq)]
+pub struct ReprData {
+ pub kind: ReprKind,
+ pub packed: bool,
+ pub align: Option<NonZeroU32>,
}
fn repr_from_value(
@@ -74,25 +87,71 @@ fn repr_from_value(
krate: CrateId,
item_tree: &ItemTree,
of: AttrOwner,
-) -> Option<ReprKind> {
+) -> Option<ReprData> {
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
}
-fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
+fn parse_repr_tt(tt: &Subtree) -> Option<ReprData> {
match tt.delimiter {
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
_ => return None,
}
- let mut it = tt.token_trees.iter();
- match it.next()? {
- TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
- _ => Some(ReprKind::Other),
+ let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
+
+ let mut tts = tt.token_trees.iter().peekable();
+ while let Some(tt) = tts.next() {
+ if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
+ match &*ident.text {
+ "packed" => {
+ data.packed = true;
+ if let Some(TokenTree::Subtree(_)) = tts.peek() {
+ tts.next();
+ }
+ }
+ "align" => {
+ if let Some(TokenTree::Subtree(tt)) = tts.peek() {
+ tts.next();
+ if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
+ if let Ok(align) = lit.text.parse() {
+ data.align = Some(align);
+ }
+ }
+ }
+ }
+ "C" => {
+ if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
+ *is_c = true;
+ } else {
+ data.kind = ReprKind::C;
+ }
+ }
+ "transparent" => data.kind = ReprKind::Transparent,
+ repr => {
+ let is_c = matches!(data.kind, ReprKind::C);
+ if let Some(builtin) = BuiltinInt::from_suffix(repr)
+ .map(Either::Left)
+ .or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
+ {
+ data.kind = ReprKind::BuiltinInt { builtin, is_c };
+ }
+ }
+ }
+ }
}
+
+ Some(data)
}
impl StructData {
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
+ db.struct_data_with_diagnostics(id).0
+ }
+
+ pub(crate) fn struct_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ id: StructId,
+ ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
let loc = id.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
@@ -100,15 +159,35 @@ impl StructData {
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
let strukt = &item_tree[loc.id.value];
- let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
- Arc::new(StructData {
- name: strukt.name.clone(),
- variant_data: Arc::new(variant_data),
- repr,
- visibility: item_tree[strukt.visibility].clone(),
- })
+ let (variant_data, diagnostics) = lower_fields(
+ db,
+ krate,
+ loc.id.file_id(),
+ loc.container.local_id,
+ &item_tree,
+ &cfg_options,
+ &strukt.fields,
+ None,
+ );
+ (
+ Arc::new(StructData {
+ name: strukt.name.clone(),
+ variant_data: Arc::new(variant_data),
+ repr,
+ visibility: item_tree[strukt.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
+
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
+ db.union_data_with_diagnostics(id).0
+ }
+
+ pub(crate) fn union_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ id: UnionId,
+ ) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
let loc = id.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
@@ -116,56 +195,98 @@ impl StructData {
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
let union = &item_tree[loc.id.value];
- let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
-
- Arc::new(StructData {
- name: union.name.clone(),
- variant_data: Arc::new(variant_data),
- repr,
- visibility: item_tree[union.visibility].clone(),
- })
+ let (variant_data, diagnostics) = lower_fields(
+ db,
+ krate,
+ loc.id.file_id(),
+ loc.container.local_id,
+ &item_tree,
+ &cfg_options,
+ &union.fields,
+ None,
+ );
+ (
+ Arc::new(StructData {
+ name: union.name.clone(),
+ variant_data: Arc::new(variant_data),
+ repr,
+ visibility: item_tree[union.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
}
impl EnumData {
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
+ db.enum_data_with_diagnostics(e).0
+ }
+
+ pub(crate) fn enum_data_with_diagnostics_query(
+ db: &dyn DefDatabase,
+ e: EnumId,
+ ) -> (Arc<EnumData>, Arc<[DefDiagnostic]>) {
let loc = e.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+ let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
let enum_ = &item_tree[loc.id.value];
let mut variants = Arena::new();
+ let mut diagnostics = Vec::new();
for tree_id in enum_.variants.clone() {
- if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
- let var = &item_tree[tree_id];
- let var_data = lower_fields(
+ let attrs = item_tree.attrs(db, krate, tree_id.into());
+ let var = &item_tree[tree_id];
+ if attrs.is_cfg_enabled(&cfg_options) {
+ let (var_data, field_diagnostics) = lower_fields(
db,
krate,
+ loc.id.file_id(),
+ loc.container.local_id,
&item_tree,
&cfg_options,
&var.fields,
Some(enum_.visibility),
);
+ diagnostics.extend(field_diagnostics);
variants.alloc(EnumVariantData {
name: var.name.clone(),
variant_data: Arc::new(var_data),
});
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ loc.container.local_id,
+ InFile::new(loc.id.file_id(), var.ast_id.upcast()),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- Arc::new(EnumData {
- name: enum_.name.clone(),
- variants,
- visibility: item_tree[enum_.visibility].clone(),
- })
+ (
+ Arc::new(EnumData {
+ name: enum_.name.clone(),
+ variants,
+ repr,
+ visibility: item_tree[enum_.visibility].clone(),
+ }),
+ diagnostics.into(),
+ )
}
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
Some(id)
}
+
+ pub fn variant_body_type(&self) -> Either<BuiltinInt, BuiltinUint> {
+ match self.repr {
+ Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
+ _ => Either::Left(BuiltinInt::Isize),
+ }
+ }
}
impl HasChildSource<LocalEnumVariantId> for EnumId {
@@ -324,31 +445,64 @@ fn lower_struct(
fn lower_fields(
db: &dyn DefDatabase,
krate: CrateId,
+ current_file_id: HirFileId,
+ container: LocalModuleId,
item_tree: &ItemTree,
cfg_options: &CfgOptions,
fields: &Fields,
override_visibility: Option<RawVisibilityId>,
-) -> VariantData {
+) -> (VariantData, Vec<DefDiagnostic>) {
+ let mut diagnostics = Vec::new();
match fields {
Fields::Record(flds) => {
let mut arena = Arena::new();
for field_id in flds.clone() {
- if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
- arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+ let attrs = item_tree.attrs(db, krate, field_id.into());
+ let field = &item_tree[field_id];
+ if attrs.is_cfg_enabled(cfg_options) {
+ arena.alloc(lower_field(item_tree, field, override_visibility));
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ container,
+ InFile::new(
+ current_file_id,
+ match field.ast_id {
+ FieldAstId::Record(it) => it.upcast(),
+ FieldAstId::Tuple(it) => it.upcast(),
+ },
+ ),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- VariantData::Record(arena)
+ (VariantData::Record(arena), diagnostics)
}
Fields::Tuple(flds) => {
let mut arena = Arena::new();
for field_id in flds.clone() {
- if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
- arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
+ let attrs = item_tree.attrs(db, krate, field_id.into());
+ let field = &item_tree[field_id];
+ if attrs.is_cfg_enabled(cfg_options) {
+ arena.alloc(lower_field(item_tree, field, override_visibility));
+ } else {
+ diagnostics.push(DefDiagnostic::unconfigured_code(
+ container,
+ InFile::new(
+ current_file_id,
+ match field.ast_id {
+ FieldAstId::Record(it) => it.upcast(),
+ FieldAstId::Tuple(it) => it.upcast(),
+ },
+ ),
+ attrs.cfg().unwrap(),
+ cfg_options.clone(),
+ ))
}
}
- VariantData::Tuple(arena)
+ (VariantData::Tuple(arena), diagnostics)
}
- Fields::Unit => VariantData::Unit,
+ Fields::Unit => (VariantData::Unit, diagnostics),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 22f5fb992..759f3b8c0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -27,7 +27,7 @@ use crate::{
macro_id_to_def_id,
nameres::DefMap,
path::{ModPath, Path},
- src::HasSource,
+ src::{HasChildSource, HasSource},
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
UnresolvedMacro,
};
@@ -311,7 +311,20 @@ impl Body {
DefWithBodyId::FunctionId(f) => {
let f = f.lookup(db);
let src = f.source(db);
- params = src.value.param_list();
+ params = src.value.param_list().map(|param_list| {
+ let item_tree = f.id.item_tree(db);
+ let func = &item_tree[f.id.value];
+ let krate = f.container.module(db).krate;
+ let crate_graph = db.crate_graph();
+ (
+ param_list,
+ func.params.clone().map(move |param| {
+ item_tree
+ .attrs(db, krate, param.into())
+ .is_cfg_enabled(&crate_graph[krate].cfg_options)
+ }),
+ )
+ });
(src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
}
DefWithBodyId::ConstId(c) => {
@@ -324,10 +337,17 @@ impl Body {
let src = s.source(db);
(src.file_id, s.module(db), src.value.body())
}
+ DefWithBodyId::VariantId(v) => {
+ let e = v.parent.lookup(db);
+ let src = v.parent.child_source(db);
+ let variant = &src.value[v.local_id];
+ (src.file_id, e.container, variant.expr())
+ }
};
let expander = Expander::new(db, file_id, module);
let (mut body, source_map) = Body::new(db, expander, params, body);
body.shrink_to_fit();
+
(Arc::new(body), Arc::new(source_map))
}
@@ -364,7 +384,7 @@ impl Body {
fn new(
db: &dyn DefDatabase,
expander: Expander,
- params: Option<ast::ParamList>,
+ params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
lower::lower(db, expander, params, body)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 3b3297f78..ccc01c3ef 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -29,8 +29,9 @@ use crate::{
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
db::DefDatabase,
expr::{
- dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
- Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+ dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
+ Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
+ Statement,
},
intern::Interned,
item_scope::BuiltinShadowMode,
@@ -76,7 +77,7 @@ impl<'a> LowerCtx<'a> {
pub(super) fn lower(
db: &dyn DefDatabase,
expander: Expander,
- params: Option<ast::ParamList>,
+ params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
ExprCollector {
@@ -97,6 +98,7 @@ pub(super) fn lower(
name_to_pat_grouping: Default::default(),
is_lowering_inside_or_pat: false,
is_lowering_assignee_expr: false,
+ is_lowering_generator: false,
}
.collect(params, body)
}
@@ -111,16 +113,19 @@ struct ExprCollector<'a> {
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
is_lowering_inside_or_pat: bool,
is_lowering_assignee_expr: bool,
+ is_lowering_generator: bool,
}
impl ExprCollector<'_> {
fn collect(
mut self,
- param_list: Option<ast::ParamList>,
+ param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
body: Option<ast::Expr>,
) -> (Body, BodySourceMap) {
- if let Some(param_list) = param_list {
- if let Some(self_param) = param_list.self_param() {
+ if let Some((param_list, mut attr_enabled)) = param_list {
+ if let Some(self_param) =
+ param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+ {
let ptr = AstPtr::new(&self_param);
let param_pat = self.alloc_pat(
Pat::Bind {
@@ -136,7 +141,11 @@ impl ExprCollector<'_> {
self.body.params.push(param_pat);
}
- for pat in param_list.params().filter_map(|param| param.pat()) {
+ for pat in param_list
+ .params()
+ .zip(attr_enabled)
+ .filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
+ {
let param_pat = self.collect_pat(pat);
self.body.params.push(param_pat);
}
@@ -358,6 +367,7 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
}
ast::Expr::YieldExpr(e) => {
+ self.is_lowering_generator = true;
let expr = e.expr().map(|e| self.collect_expr(e));
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
}
@@ -459,13 +469,31 @@ impl ExprCollector<'_> {
.ret_type()
.and_then(|r| r.ty())
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+
+ let prev_is_lowering_generator = self.is_lowering_generator;
+ self.is_lowering_generator = false;
+
let body = self.collect_expr_opt(e.body());
+
+ let closure_kind = if self.is_lowering_generator {
+ let movability = if e.static_token().is_some() {
+ Movability::Static
+ } else {
+ Movability::Movable
+ };
+ ClosureKind::Generator(movability)
+ } else {
+ ClosureKind::Closure
+ };
+ self.is_lowering_generator = prev_is_lowering_generator;
+
self.alloc_expr(
Expr::Closure {
args: args.into(),
arg_types: arg_types.into(),
ret_type,
body,
+ closure_kind,
},
syntax_ptr,
)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index f2fed9544..162d173d5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -2,8 +2,10 @@
use std::fmt::{self, Write};
+use syntax::ast::HasName;
+
use crate::{
- expr::{Array, BindingAnnotation, Literal, Statement},
+ expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
pretty::{print_generic_args, print_path, print_type_ref},
type_ref::TypeRef,
};
@@ -32,6 +34,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
};
format!("const {} = ", name)
}
+ DefWithBodyId::VariantId(it) => {
+ needs_semi = false;
+ let src = it.parent.child_source(db);
+ let variant = &src.value[it.local_id];
+ let name = match &variant.name() {
+ Some(name) => name.to_string(),
+ None => "_".to_string(),
+ };
+ format!("{}", name)
+ }
};
let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
@@ -350,7 +362,10 @@ impl<'a> Printer<'a> {
self.print_expr(*index);
w!(self, "]");
}
- Expr::Closure { args, arg_types, ret_type, body } => {
+ Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
+ if let ClosureKind::Generator(Movability::Static) = closure_kind {
+ w!(self, "static ");
+ }
w!(self, "|");
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
if i != 0 {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
index 0e7ce5f85..39581b33a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs
@@ -379,7 +379,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
- rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+ rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
gated!(
alloc_error_handler, Normal, template!(Word), WarnFollowing,
experimental!(alloc_error_handler)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index 5b1435e8f..bb1316525 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -198,6 +198,10 @@ impl ChildBySource for EnumId {
impl ChildBySource for DefWithBodyId {
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
let body = db.body(*self);
+ if let &DefWithBodyId::VariantId(v) = self {
+ VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
+ }
+
for (_, def_map) in body.blocks(db) {
// All block expressions are merged into the same map, because they logically all add
// inner items to the containing `DefWithBodyId`.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 631ae3cf1..2dc69b00a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -219,7 +219,7 @@ impl TraitData {
pub(crate) fn trait_data_with_diagnostics_query(
db: &dyn DefDatabase,
tr: TraitId,
- ) -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>) {
+ ) -> (Arc<TraitData>, Arc<[DefDiagnostic]>) {
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
@@ -251,7 +251,7 @@ impl TraitData {
visibility,
skip_array_during_method_dispatch,
}),
- Arc::new(diagnostics),
+ diagnostics.into(),
)
}
@@ -299,7 +299,7 @@ impl ImplData {
pub(crate) fn impl_data_with_diagnostics_query(
db: &dyn DefDatabase,
id: ImplId,
- ) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>) {
+ ) -> (Arc<ImplData>, Arc<[DefDiagnostic]>) {
let _p = profile::span("impl_data_with_diagnostics_query");
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
@@ -318,7 +318,7 @@ impl ImplData {
(
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
- Arc::new(diagnostics),
+ diagnostics.into(),
)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 40b2f734b..431c82554 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -97,24 +97,33 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
#[salsa::invoke(StructData::struct_data_query)]
fn struct_data(&self, id: StructId) -> Arc<StructData>;
+ #[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
+ fn struct_data_with_diagnostics(&self, id: StructId)
+ -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(StructData::union_data_query)]
fn union_data(&self, id: UnionId) -> Arc<StructData>;
+ #[salsa::invoke(StructData::union_data_with_diagnostics_query)]
+ fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(EnumData::enum_data_query)]
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
+ #[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
+ fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc<EnumData>, Arc<[DefDiagnostic]>);
+
#[salsa::invoke(ImplData::impl_data_query)]
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
#[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
- fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>);
+ fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<[DefDiagnostic]>);
#[salsa::invoke(TraitData::trait_data_query)]
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
#[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
- fn trait_data_with_diagnostics(&self, tr: TraitId)
- -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>);
+ fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>);
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index 419d3feec..162646550 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -198,6 +198,7 @@ pub enum Expr {
arg_types: Box<[Option<Interned<TypeRef>>]>,
ret_type: Option<Interned<TypeRef>>,
body: ExprId,
+ closure_kind: ClosureKind,
},
Tuple {
exprs: Box<[ExprId]>,
@@ -211,6 +212,18 @@ pub enum Expr {
Underscore,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ClosureKind {
+ Closure,
+ Generator(Movability),
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Movability {
+ Static,
+ Movable,
+}
+
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Array {
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 89e961f84..c70e6fdcc 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1,6 +1,6 @@
//! An algorithm to find a path to refer to a certain item.
-use std::iter;
+use std::{cmp::Ordering, iter};
use hir_expand::name::{known, AsName, Name};
use rustc_hash::FxHashSet;
@@ -16,9 +16,14 @@ use crate::{
/// Find a path that can be used to refer to a certain item. This can depend on
/// *from where* you're referring to the item, hence the `from` parameter.
-pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
+pub fn find_path(
+ db: &dyn DefDatabase,
+ item: ItemInNs,
+ from: ModuleId,
+ prefer_no_std: bool,
+) -> Option<ModPath> {
let _p = profile::span("find_path");
- find_path_inner(db, item, from, None)
+ find_path_inner(db, item, from, None, prefer_no_std)
}
pub fn find_path_prefixed(
@@ -26,47 +31,14 @@ pub fn find_path_prefixed(
item: ItemInNs,
from: ModuleId,
prefix_kind: PrefixKind,
+ prefer_no_std: bool,
) -> Option<ModPath> {
let _p = profile::span("find_path_prefixed");
- find_path_inner(db, item, from, Some(prefix_kind))
+ find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
}
const MAX_PATH_LEN: usize = 15;
-trait ModPathExt {
- fn starts_with_std(&self) -> bool;
- fn can_start_with_std(&self) -> bool;
-}
-
-impl ModPathExt for ModPath {
- fn starts_with_std(&self) -> bool {
- self.segments().first() == Some(&known::std)
- }
-
- // Can we replace the first segment with `std::` and still get a valid, identical path?
- fn can_start_with_std(&self) -> bool {
- let first_segment = self.segments().first();
- first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
- }
-}
-
-fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
- if item == ItemInNs::Types(from.into()) {
- // - if the item is the module we're in, use `self`
- Some(ModPath::from_segments(PathKind::Super(0), None))
- } else if let Some(parent_id) = def_map[from.local_id].parent {
- // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
- let parent_id = def_map.module_id(parent_id);
- if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
- Some(ModPath::from_segments(PathKind::Super(1), None))
- } else {
- None
- }
- } else {
- None
- }
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PrefixKind {
/// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
@@ -94,135 +66,247 @@ impl PrefixKind {
self == &PrefixKind::ByCrate
}
}
+
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
fn find_path_inner(
db: &dyn DefDatabase,
item: ItemInNs,
from: ModuleId,
prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
) -> Option<ModPath> {
- // FIXME: Do fast path for std/core libs?
+ // - if the item is a builtin, it's in scope
+ if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
+ return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
+ }
- let mut visited_modules = FxHashSet::default();
let def_map = from.def_map(db);
- find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
+ let crate_root = def_map.crate_root(db);
+ // - if the item is a module, jump straight to module search
+ if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
+ let mut visited_modules = FxHashSet::default();
+ return find_path_for_module(
+ db,
+ &def_map,
+ &mut visited_modules,
+ crate_root,
+ from,
+ module_id,
+ MAX_PATH_LEN,
+ prefixed,
+ prefer_no_std || db.crate_supports_no_std(crate_root.krate),
+ );
+ }
+
+ // - if the item is already in scope, return the name under which it is
+ let scope_name = find_in_scope(db, &def_map, from, item);
+ if prefixed.is_none() {
+ if let Some(scope_name) = scope_name {
+ return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
+ }
+ }
+
+ // - if the item is in the prelude, return the name from there
+ if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
+ return value;
+ }
+
+ if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
+ // - if the item is an enum variant, refer to it via the enum
+ if let Some(mut path) = find_path_inner(
+ db,
+ ItemInNs::Types(variant.parent.into()),
+ from,
+ prefixed,
+ prefer_no_std,
+ ) {
+ let data = db.enum_data(variant.parent);
+ path.push_segment(data.variants[variant.local_id].name.clone());
+ return Some(path);
+ }
+ // If this doesn't work, it seems we have no way of referring to the
+ // enum; that's very weird, but there might still be a reexport of the
+ // variant somewhere
+ }
+
+ let mut visited_modules = FxHashSet::default();
+
+ calculate_best_path(
+ db,
+ &def_map,
+ &mut visited_modules,
+ crate_root,
+ MAX_PATH_LEN,
+ item,
+ from,
+ prefixed,
+ prefer_no_std || db.crate_supports_no_std(crate_root.krate),
+ scope_name,
+ )
}
-fn find_path_inner_(
+fn find_path_for_module(
db: &dyn DefDatabase,
def_map: &DefMap,
+ visited_modules: &mut FxHashSet<ModuleId>,
+ crate_root: ModuleId,
from: ModuleId,
- item: ItemInNs,
+ module_id: ModuleId,
max_len: usize,
- mut prefixed: Option<PrefixKind>,
- visited_modules: &mut FxHashSet<ModuleId>,
+ prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
) -> Option<ModPath> {
if max_len == 0 {
return None;
}
// Base cases:
-
// - if the item is already in scope, return the name under which it is
- let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
- def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
- });
+ let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
if prefixed.is_none() {
if let Some(scope_name) = scope_name {
return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
}
}
- // - if the item is a builtin, it's in scope
- if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
- return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
- }
-
// - if the item is the crate root, return `crate`
- let crate_root = def_map.crate_root(db);
- if item == ItemInNs::Types(ModuleDefId::ModuleId(crate_root)) {
+ if module_id == crate_root {
return Some(ModPath::from_segments(PathKind::Crate, None));
}
+ // - if relative paths are fine, check if we are searching for a parent
if prefixed.filter(PrefixKind::is_absolute).is_none() {
- if let modpath @ Some(_) = check_self_super(&def_map, item, from) {
+ if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
return modpath;
}
}
// - if the item is the crate root of a dependency crate, return the name from the extern prelude
let root_def_map = crate_root.def_map(db);
- if let ItemInNs::Types(ModuleDefId::ModuleId(item)) = item {
- for (name, &def_id) in root_def_map.extern_prelude() {
- if item == def_id {
- let name = scope_name.unwrap_or_else(|| name.clone());
-
- let name_already_occupied_in_type_ns = def_map
- .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
- def_map[local_id]
- .scope
- .type_(&name)
- .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
- })
- .is_some();
- let kind = if name_already_occupied_in_type_ns {
- cov_mark::hit!(ambiguous_crate_start);
- PathKind::Abs
- } else {
- PathKind::Plain
- };
- return Some(ModPath::from_segments(kind, Some(name)));
- }
+ for (name, &def_id) in root_def_map.extern_prelude() {
+ if module_id == def_id {
+ let name = scope_name.unwrap_or_else(|| name.clone());
+
+ let name_already_occupied_in_type_ns = def_map
+ .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map[local_id]
+ .scope
+ .type_(&name)
+ .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
+ })
+ .is_some();
+ let kind = if name_already_occupied_in_type_ns {
+ cov_mark::hit!(ambiguous_crate_start);
+ PathKind::Abs
+ } else {
+ PathKind::Plain
+ };
+ return Some(ModPath::from_segments(kind, Some(name)));
}
}
- // - if the item is in the prelude, return the name from there
+ if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
+ {
+ return value;
+ }
+ calculate_best_path(
+ db,
+ def_map,
+ visited_modules,
+ crate_root,
+ max_len,
+ ItemInNs::Types(module_id.into()),
+ from,
+ prefixed,
+ prefer_no_std,
+ scope_name,
+ )
+}
+
+fn find_in_scope(
+ db: &dyn DefDatabase,
+ def_map: &DefMap,
+ from: ModuleId,
+ item: ItemInNs,
+) -> Option<Name> {
+ def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+ def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
+ })
+}
+
+fn find_in_prelude(
+ db: &dyn DefDatabase,
+ root_def_map: &DefMap,
+ item: ItemInNs,
+ from: ModuleId,
+) -> Option<Option<ModPath>> {
if let Some(prelude_module) = root_def_map.prelude() {
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
let prelude_def_map = prelude_module.def_map(db);
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
if let Some((name, vis)) = prelude_scope.name_of(item) {
if vis.is_visible_from(db, from) {
- return Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())));
+ return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
}
}
}
+ None
+}
- // Recursive case:
- // - if the item is an enum variant, refer to it via the enum
- if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
- if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
- let data = db.enum_data(variant.parent);
- path.push_segment(data.variants[variant.local_id].name.clone());
- return Some(path);
+fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
+ if item == from {
+ // - if the item is the module we're in, use `self`
+ Some(ModPath::from_segments(PathKind::Super(0), None))
+ } else if let Some(parent_id) = def_map[from.local_id].parent {
+ // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
+ let parent_id = def_map.module_id(parent_id);
+ if item == parent_id {
+ Some(ModPath::from_segments(PathKind::Super(1), None))
+ } else {
+ None
}
- // If this doesn't work, it seems we have no way of referring to the
- // enum; that's very weird, but there might still be a reexport of the
- // variant somewhere
+ } else {
+ None
}
+}
- // - otherwise, look for modules containing (reexporting) it and import it from one of those
- let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
+fn calculate_best_path(
+ db: &dyn DefDatabase,
+ def_map: &DefMap,
+ visited_modules: &mut FxHashSet<ModuleId>,
+ crate_root: ModuleId,
+ max_len: usize,
+ item: ItemInNs,
+ from: ModuleId,
+ mut prefixed: Option<PrefixKind>,
+ prefer_no_std: bool,
+ scope_name: Option<Name>,
+) -> Option<ModPath> {
+ if max_len <= 1 {
+ return None;
+ }
let mut best_path = None;
- let mut best_path_len = max_len;
-
+ // Recursive case:
+ // - otherwise, look for modules containing (reexporting) it and import it from one of those
if item.krate(db) == Some(from.krate) {
+ let mut best_path_len = max_len;
// Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case.
- // FIXME: this should have a fast path that doesn't look through the prelude again?
for (module_id, name) in find_local_import_locations(db, item, from) {
if !visited_modules.insert(module_id) {
cov_mark::hit!(recursive_imports);
continue;
}
- if let Some(mut path) = find_path_inner_(
+ if let Some(mut path) = find_path_for_module(
db,
def_map,
+ visited_modules,
+ crate_root,
from,
- ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
+ module_id,
best_path_len - 1,
prefixed,
- visited_modules,
+ prefer_no_std,
) {
path.push_segment(name);
@@ -245,14 +329,16 @@ fn find_path_inner_(
import_map.import_info_for(item).and_then(|info| {
// Determine best path for containing module and append last segment from `info`.
// FIXME: we should guide this to look up the path locally, or from the same crate again?
- let mut path = find_path_inner_(
+ let mut path = find_path_for_module(
db,
def_map,
+ visited_modules,
+ crate_root,
from,
- ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
- best_path_len - 1,
+ info.container,
+ max_len - 1,
prefixed,
- visited_modules,
+ prefer_no_std,
)?;
cov_mark::hit!(partially_imported);
path.push_segment(info.path.segments.last()?.clone());
@@ -268,16 +354,12 @@ fn find_path_inner_(
best_path = Some(new_path);
}
}
-
- // If the item is declared inside a block expression, don't use a prefix, as we don't handle
- // that correctly (FIXME).
- if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
- if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
+ if let Some(module) = item.module(db) {
+ if module.def_map(db).block_id().is_some() && prefixed.is_some() {
cov_mark::hit!(prefixed_in_block_expression);
prefixed = Some(PrefixKind::Plain);
}
}
-
match prefixed.map(PrefixKind::prefix) {
Some(prefix) => best_path.or_else(|| {
scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
@@ -287,29 +369,48 @@ fn find_path_inner_(
}
fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
- if old_path.starts_with_std() && new_path.can_start_with_std() {
- if prefer_no_std {
- cov_mark::hit!(prefer_no_std_paths);
- new_path
- } else {
- cov_mark::hit!(prefer_std_paths);
- old_path
+ const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
+ match (old_path.segments().first(), new_path.segments().first()) {
+ (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
+ let rank = match prefer_no_std {
+ false => |name: &Name| match name {
+ name if name == &known::core => 0,
+ name if name == &known::alloc => 0,
+ name if name == &known::std => 1,
+ _ => unreachable!(),
+ },
+ true => |name: &Name| match name {
+ name if name == &known::core => 2,
+ name if name == &known::alloc => 1,
+ name if name == &known::std => 0,
+ _ => unreachable!(),
+ },
+ };
+ let nrank = rank(new);
+ let orank = rank(old);
+ match nrank.cmp(&orank) {
+ Ordering::Less => old_path,
+ Ordering::Equal => {
+ if new_path.len() < old_path.len() {
+ new_path
+ } else {
+ old_path
+ }
+ }
+ Ordering::Greater => new_path,
+ }
}
- } else if new_path.starts_with_std() && old_path.can_start_with_std() {
- if prefer_no_std {
- cov_mark::hit!(prefer_no_std_paths);
- old_path
- } else {
- cov_mark::hit!(prefer_std_paths);
- new_path
+ _ => {
+ if new_path.len() < old_path.len() {
+ new_path
+ } else {
+ old_path
+ }
}
- } else if new_path.len() < old_path.len() {
- new_path
- } else {
- old_path
}
}
+// FIXME: Remove allocations
/// Finds locations in `from.krate` from which `item` can be imported by `from`.
fn find_local_import_locations(
db: &dyn DefDatabase,
@@ -428,7 +529,8 @@ mod tests {
.take_types()
.unwrap();
- let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
+ let found_path =
+ find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
}
@@ -468,8 +570,8 @@ $0
"#,
"E::A",
"E::A",
- "E::A",
- "E::A",
+ "crate::E::A",
+ "self::E::A",
);
}
@@ -788,7 +890,6 @@ pub use super::foo;
#[test]
fn prefer_std_paths_over_alloc() {
- cov_mark::check!(prefer_std_paths);
check_found_path(
r#"
//- /main.rs crate:main deps:alloc,std
@@ -813,7 +914,6 @@ pub mod sync {
#[test]
fn prefer_core_paths_over_std() {
- cov_mark::check!(prefer_no_std_paths);
check_found_path(
r#"
//- /main.rs crate:main deps:core,std
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index a11a92204..7721221c4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -18,7 +18,7 @@ use crate::{
ConstId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
};
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub(crate) enum ImportType {
Glob,
Named,
@@ -302,13 +302,13 @@ impl ItemScope {
$changed = true;
}
Entry::Occupied(mut entry)
- if $glob_imports.$field.contains(&$lookup)
- && matches!($def_import_type, ImportType::Named) =>
+ if matches!($def_import_type, ImportType::Named) =>
{
- cov_mark::hit!(import_shadowed);
- $glob_imports.$field.remove(&$lookup);
- entry.insert(fld);
- $changed = true;
+ if $glob_imports.$field.remove(&$lookup) {
+ cov_mark::hit!(import_shadowed);
+ entry.insert(fld);
+ $changed = true;
+ }
}
_ => {}
}
@@ -457,8 +457,15 @@ impl ItemInNs {
/// Returns the crate defining this item (or `None` if `self` is built-in).
pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
match self {
- ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
+ ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
ItemInNs::Macros(id) => Some(id.module(db).krate),
}
}
+
+ pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
+ match self {
+ ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
+ ItemInNs::Macros(id) => Some(id.module(db)),
+ }
+ }
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 3342d4db4..570344596 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -943,6 +943,7 @@ impl AssocItem {
pub struct Variant {
pub name: Name,
pub fields: Fields,
+ pub ast_id: FileAstId<ast::Variant>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -952,10 +953,17 @@ pub enum Fields {
Unit,
}
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum FieldAstId {
+ Record(FileAstId<ast::RecordField>),
+ Tuple(FileAstId<ast::TupleField>),
+}
+
/// A single field of an enum variant or struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
pub name: Name,
pub type_ref: Interned<TypeRef>,
pub visibility: RawVisibilityId,
+ pub ast_id: FieldAstId,
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 7f2551e94..077a1b619 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
let name = field.name()?.as_name();
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
- let res = Field { name, type_ref, visibility };
+ let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
+ let res = Field { name, type_ref, visibility, ast_id };
Some(res)
}
@@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
let name = Name::new_tuple_field(idx);
let visibility = self.lower_visibility(field);
let type_ref = self.lower_type_ref_opt(field.ty());
- Field { name, type_ref, visibility }
+ let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
+ Field { name, type_ref, visibility, ast_id }
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
@@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
let name = variant.name()?.as_name();
let fields = self.lower_fields(&variant.kind());
- let res = Variant { name, fields };
+ let ast_id = self.source_ast_id_map.ast_id(variant);
+ let res = Variant { name, fields, ast_id };
Some(res)
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 34dd817fd..da1643152 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
w!(self, "{{");
self.indented(|this| {
for field in fields.clone() {
- let Field { visibility, name, type_ref } = &this.tree[field];
+ let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
this.print_attrs_of(field);
this.print_visibility(*visibility);
w!(this, "{}: ", name);
@@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
w!(self, "(");
self.indented(|this| {
for field in fields.clone() {
- let Field { visibility, name, type_ref } = &this.tree[field];
+ let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
this.print_attrs_of(field);
this.print_visibility(*visibility);
w!(this, "{}: ", name);
@@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for variant in variants.clone() {
- let Variant { name, fields } = &this.tree[variant];
+ let Variant { name, fields, ast_id: _ } = &this.tree[variant];
this.print_attrs_of(variant);
w!(this, "{}", name);
this.print_fields(fields);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 32ebfda4f..5c7aa7234 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -474,16 +474,24 @@ pub enum DefWithBodyId {
FunctionId(FunctionId),
StaticId(StaticId),
ConstId(ConstId),
+ VariantId(EnumVariantId),
}
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
+impl From<EnumVariantId> for DefWithBodyId {
+ fn from(id: EnumVariantId) -> Self {
+ DefWithBodyId::VariantId(id)
+ }
+}
+
impl DefWithBodyId {
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
match self {
DefWithBodyId::FunctionId(f) => Some(f.into()),
DefWithBodyId::StaticId(_) => None,
DefWithBodyId::ConstId(c) => Some(c.into()),
+ DefWithBodyId::VariantId(c) => Some(c.into()),
}
}
}
@@ -681,6 +689,7 @@ impl HasModule for DefWithBodyId {
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
+ DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
}
}
}
@@ -691,6 +700,7 @@ impl DefWithBodyId {
DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
+ DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index 6819e9114..fafcde25a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -12,11 +12,11 @@ fn test_copy_expand_simple() {
#[derive(Copy)]
struct Foo;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo;
-impl < > core::marker::Copy for Foo< > {}"##]],
+impl < > core::marker::Copy for Foo< > {}"#]],
);
}
@@ -33,7 +33,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro derive {}
#[rustc_builtin_macro]
@@ -41,7 +41,7 @@ macro Copy {}
#[derive(Copy)]
struct Foo;
-impl < > crate ::marker::Copy for Foo< > {}"##]],
+impl < > crate ::marker::Copy for Foo< > {}"#]],
);
}
@@ -53,11 +53,11 @@ fn test_copy_expand_with_type_params() {
#[derive(Copy)]
struct Foo<A, B>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo<A, B>;
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
);
}
@@ -70,11 +70,11 @@ fn test_copy_expand_with_lifetimes() {
#[derive(Copy)]
struct Foo<A, B, 'a, 'b>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Copy)]
struct Foo<A, B, 'a, 'b>;
-impl <T0: core::marker::Copy, T1: core::marker::Copy> core::marker::Copy for Foo<T0, T1> {}"##]],
+impl <T0: core::marker::Copy, T1: core::marker::Copy, > core::marker::Copy for Foo<T0, T1, > {}"#]],
);
}
@@ -86,10 +86,26 @@ fn test_clone_expand() {
#[derive(Clone)]
struct Foo<A, B>;
"#,
- expect![[r##"
+ expect![[r#"
#[derive(Clone)]
struct Foo<A, B>;
-impl <T0: core::clone::Clone, T1: core::clone::Clone> core::clone::Clone for Foo<T0, T1> {}"##]],
+impl <T0: core::clone::Clone, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
+ );
+}
+
+#[test]
+fn test_clone_expand_with_const_generics() {
+ check(
+ r#"
+//- minicore: derive, clone
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+"#,
+ expect![[r#"
+#[derive(Clone)]
+struct Foo<const X: usize, T>(u32);
+
+impl <const T0: usize, T1: core::clone::Clone, > core::clone::Clone for Foo<T0, T1, > {}"#]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 4f626105a..c04cd1651 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -93,12 +93,12 @@ macro_rules! option_env {() => {}}
fn main() { option_env!("TEST_ENV_VAR"); }
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! option_env {() => {}}
-fn main() { std::option::Option::None:: < &str>; }
-"##]],
+fn main() { $crate::option::Option::None:: < &str>; }
+"#]],
);
}
@@ -191,7 +191,7 @@ fn main() {
format_args!("{} {:?}", arg1(a, b, c), arg2);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -199,9 +199,9 @@ macro_rules! format_args {
}
fn main() {
- std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
+ $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
@@ -219,7 +219,7 @@ fn main() {
format_args!("{} {:?}", a::<A,B>(), b);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -227,9 +227,9 @@ macro_rules! format_args {
}
fn main() {
- std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
+ $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
@@ -248,7 +248,7 @@ fn main() {
format_args!/*+errors*/("{} {:?}", a.);
}
"#,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! format_args {
($fmt:expr) => ({ /* compiler built-in */ });
@@ -258,9 +258,9 @@ macro_rules! format_args {
fn main() {
let _ =
/* parse error: expected field name or number */
-std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
+$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
}
-"##]],
+"#]],
);
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 495bbe457..9ffc21881 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
match per_ns.types {
Some((ModuleDefId::ModuleId(m), _)) => {
self.def_map.prelude = Some(m);
+ break;
}
types => {
tracing::debug!(
@@ -2121,7 +2122,7 @@ impl ModCollector<'_, '_> {
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
let ast_id = item.ast_id(self.item_tree);
- let ast_id = InFile::new(self.file_id(), ast_id);
+ let ast_id = InFile::new(self.file_id(), ast_id.upcast());
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
self.module_id,
ast_id,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index ed7e920fd..066142291 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -4,7 +4,7 @@ use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use hir_expand::MacroCallKind;
use la_arena::Idx;
-use syntax::ast;
+use syntax::ast::{self, AnyHasAttrs};
use crate::{
attr::AttrId,
@@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
- UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
+ UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
@@ -75,7 +75,7 @@ impl DefDiagnostic {
pub fn unconfigured_code(
container: LocalModuleId,
- ast: AstId<ast::Item>,
+ ast: AstId<ast::AnyHasAttrs>,
cfg: CfgExpr,
opts: CfgOptions,
) -> Self {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 8aa5973ca..070f68371 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -839,6 +839,7 @@ impl HasResolver for DefWithBodyId {
DefWithBodyId::ConstId(c) => c.resolver(db),
DefWithBodyId::FunctionId(f) => f.resolver(db),
DefWithBodyId::StaticId(s) => s.resolver(db),
+ DefWithBodyId::VariantId(v) => v.parent.resolver(db),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
index dfd470ffc..3359c99b3 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
@@ -15,11 +15,11 @@ tracing = "0.1.35"
either = "1.7.0"
rustc-hash = "1.1.0"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-itertools = "0.10.3"
+itertools = "0.10.5"
hashbrown = { version = "0.12.1", features = [
"inline-more",
], default-features = false }
-smallvec = { version = "1.9.0", features = ["const_new"] }
+smallvec = { version = "1.10.0", features = ["const_new"] }
stdx = { path = "../stdx", version = "0.0.0" }
base-db = { path = "../base-db", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
index 11c0a6764..2b27db0e9 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
@@ -93,7 +93,12 @@ impl AstIdMap {
// trait does not change ids of top-level items, which helps caching.
bdfs(node, |it| {
let kind = it.kind();
- if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
+ if ast::Item::can_cast(kind)
+ || ast::BlockExpr::can_cast(kind)
+ || ast::Variant::can_cast(kind)
+ || ast::RecordField::can_cast(kind)
+ || ast::TupleField::can_cast(kind)
+ {
res.alloc(&it);
true
} else {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 79989bc2e..8966047c9 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -60,7 +60,8 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander>
struct BasicAdtInfo {
name: tt::Ident,
- type_or_const_params: usize,
+ /// `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
+ param_types: Vec<Option<tt::Subtree>>,
}
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@@ -92,50 +93,22 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
let name_token_id =
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
- let type_or_const_params =
- params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
- Ok(BasicAdtInfo { name: name_token, type_or_const_params })
-}
-
-fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
- let mut result = Vec::<tt::TokenTree>::with_capacity(n * 2);
- result.push(
- tt::Leaf::Punct(tt::Punct {
- char: '<',
- spacing: tt::Spacing::Alone,
- id: tt::TokenId::unspecified(),
- })
- .into(),
- );
- for i in 0..n {
- if i > 0 {
- result.push(
- tt::Leaf::Punct(tt::Punct {
- char: ',',
- spacing: tt::Spacing::Alone,
- id: tt::TokenId::unspecified(),
- })
- .into(),
- );
- }
- result.push(
- tt::Leaf::Ident(tt::Ident {
- id: tt::TokenId::unspecified(),
- text: format!("T{}", i).into(),
- })
- .into(),
- );
- result.extend(bound.iter().cloned());
- }
- result.push(
- tt::Leaf::Punct(tt::Punct {
- char: '>',
- spacing: tt::Spacing::Alone,
- id: tt::TokenId::unspecified(),
+ let param_types = params
+ .into_iter()
+ .flat_map(|param_list| param_list.type_or_const_params())
+ .map(|param| {
+ if let ast::TypeOrConstParam::Const(param) = param {
+ let ty = param
+ .ty()
+ .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
+ .unwrap_or_default();
+ Some(ty)
+ } else {
+ None
+ }
})
- .into(),
- );
- result
+ .collect();
+ Ok(BasicAdtInfo { name: name_token, param_types })
}
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
@@ -143,14 +116,27 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
Ok(info) => info,
Err(e) => return ExpandResult::only_err(e),
};
+ let (params, args): (Vec<_>, Vec<_>) = info
+ .param_types
+ .into_iter()
+ .enumerate()
+ .map(|(idx, param_ty)| {
+ let ident = tt::Leaf::Ident(tt::Ident {
+ id: tt::TokenId::unspecified(),
+ text: format!("T{idx}").into(),
+ });
+ let ident_ = ident.clone();
+ if let Some(ty) = param_ty {
+ (quote! { const #ident : #ty , }, quote! { #ident_ , })
+ } else {
+ let bound = trait_path.clone();
+ (quote! { #ident : #bound , }, quote! { #ident_ , })
+ }
+ })
+ .unzip();
let name = info.name;
- let trait_path_clone = trait_path.token_trees.clone();
- let bound = (quote! { : ##trait_path_clone }).token_trees;
- let type_params = make_type_args(info.type_or_const_params, bound);
- let type_args = make_type_args(info.type_or_const_params, Vec::new());
- let trait_path = trait_path.token_trees;
let expanded = quote! {
- impl ##type_params ##trait_path for #name ##type_args {}
+ impl < ##params > #trait_path for #name < ##args > {}
};
ExpandResult::ok(expanded)
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 8befa7f7d..7b19518e2 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -238,9 +238,9 @@ fn format_args_expand(
) -> ExpandResult<tt::Subtree> {
// We expand `format_args!("", a1, a2)` to
// ```
- // std::fmt::Arguments::new_v1(&[], &[
- // std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
- // std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
+ // $crate::fmt::Arguments::new_v1(&[], &[
+ // $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt),
+ // $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt),
// ])
// ```,
// which is still not really correct, but close enough for now
@@ -262,10 +262,10 @@ fn format_args_expand(
}
let _format_string = args.remove(0);
let arg_tts = args.into_iter().flat_map(|arg| {
- quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
+ quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), }
}.token_trees);
let expanded = quote! {
- std::fmt::Arguments::new_v1(&[], &[##arg_tts])
+ #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts])
};
ExpandResult::ok(expanded)
}
@@ -675,8 +675,8 @@ fn option_env_expand(
};
let expanded = match get_env_inner(db, arg_id, &key) {
- None => quote! { std::option::Option::None::<&str> },
- Some(s) => quote! { std::option::Some(#s) },
+ None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> },
+ Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) },
};
ExpandResult::ok(ExpandedEager::new(expanded))
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index bc97ee15c..87e4db039 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -221,8 +221,16 @@ pub fn expand_speculative(
fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
- let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
- let token = node.syntax_node().covering_element(range).into_token()?;
+ let syntax_node = node.syntax_node();
+ let token = rev_tmap
+ .ranges_by_token(token_id, token_to_map.kind())
+ .filter_map(|range| syntax_node.covering_element(range).into_token())
+ .min_by_key(|t| {
+ // prefer tokens of the same kind and text
+ // Note the inversion of the score here, as we want to prefer the first token in case
+ // of all tokens having the same score
+ (t.kind() != token_to_map.kind()) as u8 + (t.text() != token_to_map.text()) as u8
+ })?;
Some((node.syntax_node(), token))
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index fc128102f..a5b499fe8 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -811,6 +811,31 @@ impl<'a> InFile<&'a SyntaxNode> {
_ => None,
}
}
+
+ pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
+ // This kind of upmapping can only be achieved in attribute expanded files,
+ // as we don't have node inputs otherwise and therefor can't find an `N` node in the input
+ if !self.file_id.is_macro() {
+ return Some(self.map(Clone::clone));
+ } else if !self.file_id.is_attr_macro(db) {
+ return None;
+ }
+
+ if let Some(InFile { file_id, value: (first, last) }) = ascend_node_border_tokens(db, self)
+ {
+ if file_id.is_macro() {
+ let range = first.text_range().cover(last.text_range());
+ tracing::error!("Failed mapping out of macro file for {:?}", range);
+ return None;
+ }
+ // FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
+ let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
+ let kind = self.value.kind();
+ let value = anc.ancestors().find(|it| it.kind() == kind)?;
+ return Some(InFile::new(file_id, value));
+ }
+ None
+ }
}
impl InFile<SyntaxToken> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 4ce21a579..2679a1c36 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -263,6 +263,7 @@ pub mod known {
Iterator,
IntoIterator,
Item,
+ IntoIter,
Try,
Ok,
Future,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 7f143f396..ed13275ba 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -11,18 +11,19 @@ doctest = false
[dependencies]
cov-mark = "2.0.0-pre.1"
-itertools = "0.10.3"
+itertools = "0.10.5"
arrayvec = "0.7.2"
-smallvec = "1.9.0"
+smallvec = "1.10.0"
ena = "0.14.0"
tracing = "0.1.35"
rustc-hash = "1.1.0"
scoped-tls = "1.0.0"
-chalk-solve = { version = "0.84.0", default-features = false }
-chalk-ir = "0.84.0"
-chalk-recursive = { version = "0.84.0", default-features = false }
+chalk-solve = { version = "0.86.0", default-features = false }
+chalk-ir = "0.86.0"
+chalk-recursive = { version = "0.86.0", default-features = false }
+chalk-derive = "0.86.0"
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
-once_cell = "1.12.0"
+once_cell = "1.15.0"
typed-arena = "2.0.1"
stdx = { path = "../stdx", version = "0.0.0" }
@@ -37,7 +38,7 @@ limit = { path = "../limit", version = "0.0.0" }
test-utils = { path = "../test-utils" }
expect-test = "1.4.0"
tracing = "0.1.35"
-tracing-subscriber = { version = "0.3.14", default-features = false, features = [
+tracing-subscriber = { version = "0.3.16", default-features = false, features = [
"env-filter",
"registry",
] }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 344036dd8..78911d8dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -1,7 +1,7 @@
//! In certain situations, rust automatically inserts derefs as necessary: for
//! example, field accesses `foo.bar` still work when `foo` is actually a
//! reference to a type with the field `bar`. This is an approximation of the
-//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
+//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
use std::sync::Arc;
@@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
let projection = {
- let b = TyBuilder::assoc_type_projection(db, target);
+ let b = TyBuilder::subst_for_def(db, deref_trait, None);
if b.remaining() != 1 {
// the Target type + Deref trait should only have one generic parameter,
// namely Deref's Self type
return None;
}
- b.push(ty).build()
+ let deref_subst = b.push(ty).build();
+ TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
};
// Check that the type implements Deref at all
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index 94d7806cb..9ae752556 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -6,19 +6,19 @@ use chalk_ir::{
cast::{Cast, CastTo, Caster},
fold::TypeFoldable,
interner::HasInterner,
- AdtId, BoundVar, DebruijnIndex, Scalar,
+ AdtId, DebruijnIndex, Scalar,
};
use hir_def::{
- builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
- TypeAliasId,
+ builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
+ GenericDefId, TraitId, TypeAliasId,
};
use smallvec::SmallVec;
use crate::{
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
- to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
- ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
- TyDefId, TyExt, TyKind, ValueTyDefId,
+ to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
+ GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
+ ValueTyDefId,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -34,17 +34,32 @@ pub struct TyBuilder<D> {
data: D,
vec: SmallVec<[GenericArg; 2]>,
param_kinds: SmallVec<[ParamKind; 2]>,
+ parent_subst: Substitution,
}
impl<A> TyBuilder<A> {
fn with_data<B>(self, data: B) -> TyBuilder<B> {
- TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
+ TyBuilder {
+ data,
+ vec: self.vec,
+ param_kinds: self.param_kinds,
+ parent_subst: self.parent_subst,
+ }
}
}
impl<D> TyBuilder<D> {
- fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
- TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
+ fn new(
+ data: D,
+ param_kinds: SmallVec<[ParamKind; 2]>,
+ parent_subst: Option<Substitution>,
+ ) -> Self {
+ let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
+ Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
+ }
+
+ fn new_empty(data: D) -> Self {
+ TyBuilder::new(data, SmallVec::new(), None)
}
fn build_internal(self) -> (D, Substitution) {
@@ -52,13 +67,18 @@ impl<D> TyBuilder<D> {
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
self.assert_match_kind(a, e);
}
- let subst = Substitution::from_iter(Interner, self.vec);
+ let subst = Substitution::from_iter(
+ Interner,
+ self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
+ );
(self.data, subst)
}
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
+ assert!(self.remaining() > 0);
let arg = arg.cast(Interner);
let expected_kind = &self.param_kinds[self.vec.len()];
+
let arg_kind = match arg.data(Interner) {
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
@@ -68,7 +88,9 @@ impl<D> TyBuilder<D> {
}
};
assert_eq!(*expected_kind, arg_kind);
+
self.vec.push(arg);
+
self
}
@@ -79,20 +101,12 @@ impl<D> TyBuilder<D> {
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
// self.fill is inlined to make borrow checker happy
let mut this = self;
- let other = this.param_kinds.iter().skip(this.vec.len());
+ let other = &this.param_kinds[this.vec.len()..];
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
- ParamKind::Type => {
- GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
- .intern(Interner)
+ ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
+ ParamKind::Const(ty) => {
+ BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
}
- ParamKind::Const(ty) => GenericArgData::Const(
- ConstData {
- value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
- ty: ty.clone(),
- }
- .intern(Interner),
- )
- .intern(Interner),
});
this.vec.extend(filler.take(this.remaining()).casted(Interner));
assert_eq!(this.remaining(), 0);
@@ -102,8 +116,8 @@ impl<D> TyBuilder<D> {
pub fn fill_with_unknown(self) -> Self {
// self.fill is inlined to make borrow checker happy
let mut this = self;
- let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
- ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
+ let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
+ ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
});
this.vec.extend(filler.casted(Interner));
@@ -113,33 +127,17 @@ impl<D> TyBuilder<D> {
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
self.fill(|x| match x {
- ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
- ParamKind::Const(ty) => {
- GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
- }
+ ParamKind::Type => table.new_type_var().cast(Interner),
+ ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
})
}
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
- self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
+ self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
assert_eq!(self.remaining(), 0);
self
}
- pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
- assert!(self.vec.is_empty());
- assert!(parent_substs.len(Interner) <= self.param_kinds.len());
- self.extend(parent_substs.iter(Interner).cloned());
- self
- }
-
- fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
- for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
- self.assert_match_kind(&x.0, &x.1);
- }
- self.vec.extend(it);
- }
-
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
match (a.data(Interner), e) {
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
@@ -188,21 +186,42 @@ impl TyBuilder<()> {
params.placeholder_subst(db)
}
- pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
- let def = def.into();
- let params = generics(db.upcast(), def);
- TyBuilder::new(
- (),
- params
- .iter()
- .map(|(id, data)| match data {
- TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
- TypeOrConstParamData::ConstParamData(_) => {
- ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
- }
- })
- .collect(),
- )
+ pub fn subst_for_def(
+ db: &dyn HirDatabase,
+ def: impl Into<GenericDefId>,
+ parent_subst: Option<Substitution>,
+ ) -> TyBuilder<()> {
+ let generics = generics(db.upcast(), def.into());
+ assert!(generics.parent_generics().is_some() == parent_subst.is_some());
+ let params = generics
+ .iter_self()
+ .map(|(id, data)| match data {
+ TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
+ TypeOrConstParamData::ConstParamData(_) => {
+ ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
+ }
+ })
+ .collect();
+ TyBuilder::new((), params, parent_subst)
+ }
+
+ /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
+ ///
+ /// A generator's substitution consists of:
+ /// - resume type of generator
+ /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
+ /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
+ /// - generic parameters in scope on `parent`
+ /// in this order.
+ ///
+ /// This method prepopulates the builder with placeholder substitution of `parent`, so you
+ /// should only push exactly 3 `GenericArg`s before building.
+ pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
+ let parent_subst =
+ parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
+ // These represent resume type, yield type, and return type of generator.
+ let params = std::iter::repeat(ParamKind::Type).take(3).collect();
+ TyBuilder::new((), params, parent_subst)
}
pub fn build(self) -> Substitution {
@@ -213,7 +232,7 @@ impl TyBuilder<()> {
impl TyBuilder<hir_def::AdtId> {
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
- TyBuilder::subst_for_def(db, def).with_data(def)
+ TyBuilder::subst_for_def(db, def, None).with_data(def)
}
pub fn fill_with_defaults(
@@ -221,16 +240,27 @@ impl TyBuilder<hir_def::AdtId> {
db: &dyn HirDatabase,
mut fallback: impl FnMut() -> Ty,
) -> Self {
+ // Note that we're building ADT, so we never have parent generic parameters.
let defaults = db.generic_defaults(self.data.into());
+ let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
for default_ty in defaults.iter().skip(self.vec.len()) {
- if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
+ // NOTE(skip_binders): we only check if the arg type is error type.
+ if let Some(x) = default_ty.skip_binders().ty(Interner) {
if x.is_unknown() {
self.vec.push(fallback().cast(Interner));
continue;
}
- };
- // each default can depend on the previous parameters
- let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
+ }
+ // Each default can only depend on the previous parameters.
+ // FIXME: we don't handle const generics here.
+ let subst_so_far = Substitution::from_iter(
+ Interner,
+ self.vec
+ .iter()
+ .cloned()
+ .chain(iter::repeat(dummy_ty.clone()))
+ .take(self.param_kinds.len()),
+ );
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
}
self
@@ -245,7 +275,7 @@ impl TyBuilder<hir_def::AdtId> {
pub struct Tuple(usize);
impl TyBuilder<Tuple> {
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
- TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
+ TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
}
pub fn build(self) -> Ty {
@@ -256,7 +286,7 @@ impl TyBuilder<Tuple> {
impl TyBuilder<TraitId> {
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
- TyBuilder::subst_for_def(db, def).with_data(def)
+ TyBuilder::subst_for_def(db, def, None).with_data(def)
}
pub fn build(self) -> TraitRef {
@@ -266,8 +296,12 @@ impl TyBuilder<TraitId> {
}
impl TyBuilder<TypeAliasId> {
- pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
- TyBuilder::subst_for_def(db, def).with_data(def)
+ pub fn assoc_type_projection(
+ db: &dyn HirDatabase,
+ def: TypeAliasId,
+ parent_subst: Option<Substitution>,
+ ) -> TyBuilder<TypeAliasId> {
+ TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
}
pub fn build(self) -> ProjectionTy {
@@ -277,19 +311,6 @@ impl TyBuilder<TypeAliasId> {
}
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
- fn subst_binders(b: Binders<T>) -> Self {
- let param_kinds = b
- .binders
- .iter(Interner)
- .map(|x| match x {
- chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
- chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
- chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
- })
- .collect();
- TyBuilder::new(b, param_kinds)
- }
-
pub fn build(self) -> T {
let (b, subst) = self.build_internal();
b.substitute(Interner, &subst)
@@ -297,15 +318,41 @@ impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Bin
}
impl TyBuilder<Binders<Ty>> {
- pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
- TyBuilder::subst_binders(db.ty(def))
+ pub fn def_ty(
+ db: &dyn HirDatabase,
+ def: TyDefId,
+ parent_subst: Option<Substitution>,
+ ) -> TyBuilder<Binders<Ty>> {
+ let poly_ty = db.ty(def);
+ let id: GenericDefId = match def {
+ TyDefId::BuiltinType(_) => {
+ assert!(parent_subst.is_none());
+ return TyBuilder::new_empty(poly_ty);
+ }
+ TyDefId::AdtId(id) => id.into(),
+ TyDefId::TypeAliasId(id) => id.into(),
+ };
+ TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
}
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
- TyBuilder::subst_binders(db.impl_self_ty(def))
+ TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
}
- pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
- TyBuilder::subst_binders(db.value_ty(def))
+ pub fn value_ty(
+ db: &dyn HirDatabase,
+ def: ValueTyDefId,
+ parent_subst: Option<Substitution>,
+ ) -> TyBuilder<Binders<Ty>> {
+ let poly_value_ty = db.value_ty(def);
+ let id = match def.to_generic_def_id() {
+ Some(id) => id,
+ None => {
+ // static items
+ assert!(parent_subst.is_none());
+ return TyBuilder::new_empty(poly_value_ty);
+ }
+ };
+ TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index faec99c7d..43c3451ca 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId;
use hir_def::{
+ expr::Movability,
lang_item::{lang_attr, LangItemTarget},
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
};
@@ -26,9 +27,9 @@ use crate::{
to_assoc_type_id, to_chalk_trait_id,
traits::ChalkContext,
utils::generics,
- AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
- ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
- TyExt, TyKind, WhereClause,
+ wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
+ Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
+ TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
};
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
@@ -372,17 +373,62 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
}
fn generator_datum(
&self,
- _: chalk_ir::GeneratorId<Interner>,
+ id: chalk_ir::GeneratorId<Interner>,
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
- // FIXME
- unimplemented!()
+ let (parent, expr) = self.db.lookup_intern_generator(id.into());
+
+ // We fill substitution with unknown type, because we only need to know whether the generic
+ // params are types or consts to build `Binders` and those being filled up are for
+ // `resume_type`, `yield_type`, and `return_type` of the generator in question.
+ let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
+
+ let input_output = rust_ir::GeneratorInputOutputDatum {
+ resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
+ .intern(Interner),
+ yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
+ .intern(Interner),
+ return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
+ .intern(Interner),
+ // FIXME: calculate upvars
+ upvars: vec![],
+ };
+
+ let it = subst
+ .iter(Interner)
+ .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
+ let input_output = crate::make_type_and_const_binders(it, input_output);
+
+ let movability = match self.db.body(parent)[expr] {
+ hir_def::expr::Expr::Closure {
+ closure_kind: hir_def::expr::ClosureKind::Generator(movability),
+ ..
+ } => movability,
+ _ => unreachable!("non generator expression interned as generator"),
+ };
+ let movability = match movability {
+ Movability::Static => rust_ir::Movability::Static,
+ Movability::Movable => rust_ir::Movability::Movable,
+ };
+
+ Arc::new(rust_ir::GeneratorDatum { movability, input_output })
}
fn generator_witness_datum(
&self,
- _: chalk_ir::GeneratorId<Interner>,
+ id: chalk_ir::GeneratorId<Interner>,
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
- // FIXME
- unimplemented!()
+ // FIXME: calculate inner types
+ let inner_types =
+ rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
+
+ let (parent, _) = self.db.lookup_intern_generator(id.into());
+ // See the comment in `generator_datum()` for unknown types.
+ let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
+ let it = subst
+ .iter(Interner)
+ .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
+ let inner_types = crate::make_type_and_const_binders(it, inner_types);
+
+ Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
}
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
@@ -429,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
let ctx = crate::TyLoweringContext::new(db, &resolver)
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
- let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
+
+ let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
+ .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
+ .build();
+ let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
.build();
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
+
let mut bounds: Vec<_> = type_alias_data
.bounds
.iter()
@@ -772,10 +823,10 @@ pub(super) fn generic_predicate_to_inline_bound(
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
}
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
- if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in {
+ let trait_ = projection_ty.trait_(db);
+ if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
return None;
}
- let trait_ = projection_ty.trait_(db);
let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
.iter()
.map(|ty| ty.clone().cast(Interner))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 4a5533c64..e2099d7e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -152,7 +152,7 @@ impl TyExt for Ty {
TyKind::FnDef(def, parameters) => {
let callable_def = db.lookup_intern_callable_def((*def).into());
let sig = db.callable_item_signature(callable_def);
- Some(sig.substitute(Interner, &parameters))
+ Some(sig.substitute(Interner, parameters))
}
TyKind::Closure(.., substs) => {
let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
@@ -166,6 +166,8 @@ impl TyExt for Ty {
let trait_ref = match self.kind(Interner) {
// The principal trait bound should be the first element of the bounds. This is an
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
+ // FIXME: dyn types may not have principal trait and we don't want to return auto trait
+ // here.
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
match b.skip_binders() {
WhereClause::Implemented(trait_ref) => Some(trait_ref),
@@ -260,7 +262,7 @@ impl TyExt for Ty {
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
- }) => &proj.self_type_parameter(Interner) == self,
+ }) => &proj.self_type_parameter(db) == self,
_ => false,
})
.collect::<Vec<_>>();
@@ -331,6 +333,7 @@ impl TyExt for Ty {
pub trait ProjectionTyExt {
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
+ fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
}
impl ProjectionTyExt for ProjectionTy {
@@ -347,6 +350,10 @@ impl ProjectionTyExt for ProjectionTy {
_ => panic!("projection ty without parent trait"),
}
}
+
+ fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
+ self.trait_ref(db).self_type_parameter(Interner)
+ }
}
pub trait TraitRefExt {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 6ecb6e6fd..2c0c6e0b8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -7,14 +7,17 @@ use std::{
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
use hir_def::{
+ builtin_type::BuiltinInt,
expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId},
path::ModPath,
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
+ src::HasChildSource,
type_ref::ConstScalar,
- ConstId, DefWithBodyId,
+ ConstId, DefWithBodyId, EnumVariantId, Lookup,
};
-use la_arena::{Arena, Idx};
+use la_arena::{Arena, Idx, RawIdx};
use stdx::never;
+use syntax::ast::HasName;
use crate::{
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
@@ -77,6 +80,7 @@ pub enum ConstEvalError {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ComputedExpr {
Literal(Literal),
+ Enum(String, EnumVariantId, Literal),
Tuple(Box<[ComputedExpr]>),
}
@@ -104,6 +108,7 @@ impl Display for ComputedExpr {
Literal::String(x) => std::fmt::Debug::fmt(x, f),
Literal::ByteString(x) => std::fmt::Debug::fmt(x, f),
},
+ ComputedExpr::Enum(name, _, _) => name.fmt(f),
ComputedExpr::Tuple(t) => {
f.write_char('(')?;
for x in &**t {
@@ -148,13 +153,51 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
}
}
+fn get_name(ctx: &mut ConstEvalCtx<'_>, variant: EnumVariantId) -> String {
+ let loc = variant.parent.lookup(ctx.db.upcast());
+ let children = variant.parent.child_source(ctx.db.upcast());
+ let item_tree = loc.id.item_tree(ctx.db.upcast());
+
+ let variant_name = children.value[variant.local_id].name();
+ let enum_name = item_tree[loc.id.value].name.to_string();
+ enum_name + "::" + &variant_name.unwrap().to_string()
+}
+
pub fn eval_const(
expr_id: ExprId,
ctx: &mut ConstEvalCtx<'_>,
) -> Result<ComputedExpr, ConstEvalError> {
+ let u128_to_i128 = |it: u128| -> Result<i128, ConstEvalError> {
+ it.try_into().map_err(|_| ConstEvalError::NotSupported("u128 is too big"))
+ };
+
let expr = &ctx.exprs[expr_id];
match expr {
- Expr::Missing => Err(ConstEvalError::IncompleteExpr),
+ Expr::Missing => match ctx.owner {
+ // evaluate the implicit variant index of an enum variant without expression
+ // FIXME: This should return the type of the enum representation
+ DefWithBodyId::VariantId(variant) => {
+ let prev_idx: u32 = variant.local_id.into_raw().into();
+ let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
+ let value = match prev_idx {
+ Some(local_id) => {
+ let prev_variant = EnumVariantId { local_id, parent: variant.parent };
+ 1 + match ctx.db.const_eval_variant(prev_variant)? {
+ ComputedExpr::Literal(Literal::Int(v, _)) => v,
+ ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
+ _ => {
+ return Err(ConstEvalError::NotSupported(
+ "Enum can't contain this kind of value",
+ ))
+ }
+ }
+ }
+ _ => 0,
+ };
+ Ok(ComputedExpr::Literal(Literal::Int(value, Some(BuiltinInt::I128))))
+ }
+ _ => Err(ConstEvalError::IncompleteExpr),
+ },
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
&Expr::UnaryOp { expr, op } => {
let ty = &ctx.expr_ty(expr);
@@ -167,9 +210,7 @@ pub fn eval_const(
return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
}
ComputedExpr::Literal(Literal::Int(v, _)) => v,
- ComputedExpr::Literal(Literal::Uint(v, _)) => v
- .try_into()
- .map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
+ ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
};
let r = match ty.kind(Interner) {
@@ -198,9 +239,7 @@ pub fn eval_const(
hir_def::expr::UnaryOp::Neg => {
let v = match ev {
ComputedExpr::Literal(Literal::Int(v, _)) => v,
- ComputedExpr::Literal(Literal::Uint(v, _)) => v
- .try_into()
- .map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
+ ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
};
Ok(ComputedExpr::Literal(Literal::Int(
@@ -219,16 +258,12 @@ pub fn eval_const(
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
let v1 = match lhs {
ComputedExpr::Literal(Literal::Int(v, _)) => v,
- ComputedExpr::Literal(Literal::Uint(v, _)) => {
- v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
- }
+ ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
};
let v2 = match rhs {
ComputedExpr::Literal(Literal::Int(v, _)) => v,
- ComputedExpr::Literal(Literal::Uint(v, _)) => {
- v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
- }
+ ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
};
match op {
@@ -339,9 +374,22 @@ pub fn eval_const(
ValueNs::GenericParam(_) => {
Err(ConstEvalError::NotSupported("const generic without substitution"))
}
+ ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? {
+ ComputedExpr::Literal(lit) => {
+ Ok(ComputedExpr::Enum(get_name(ctx, id), id, lit))
+ }
+ _ => Err(ConstEvalError::NotSupported(
+ "Enums can't evalute to anything but numbers",
+ )),
+ },
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
}
}
+ // FIXME: Handle the cast target
+ &Expr::Cast { expr, .. } => match eval_const(expr, ctx)? {
+ ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)),
+ _ => Err(ConstEvalError::NotSupported("Can't cast these types")),
+ },
_ => Err(ConstEvalError::NotSupported("This kind of expression")),
}
}
@@ -412,7 +460,15 @@ pub(crate) fn const_eval_recover(
Err(ConstEvalError::Loop)
}
-pub(crate) fn const_eval_query(
+pub(crate) fn const_eval_variant_recover(
+ _: &dyn HirDatabase,
+ _: &[String],
+ _: &EnumVariantId,
+) -> Result<ComputedExpr, ConstEvalError> {
+ Err(ConstEvalError::Loop)
+}
+
+pub(crate) fn const_eval_variant_query(
db: &dyn HirDatabase,
const_id: ConstId,
) -> Result<ComputedExpr, ConstEvalError> {
@@ -433,6 +489,26 @@ pub(crate) fn const_eval_query(
result
}
+pub(crate) fn const_eval_query_variant(
+ db: &dyn HirDatabase,
+ variant_id: EnumVariantId,
+) -> Result<ComputedExpr, ConstEvalError> {
+ let def = variant_id.into();
+ let body = db.body(def);
+ let infer = &db.infer(def);
+ eval_const(
+ body.body_expr,
+ &mut ConstEvalCtx {
+ db,
+ owner: def,
+ exprs: &body.exprs,
+ pats: &body.pats,
+ local_data: HashMap::default(),
+ infer,
+ },
+ )
+}
+
pub(crate) fn eval_to_const<'a>(
expr: Idx<Expr>,
mode: ParamLoweringMode,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 4a052851a..b76506f6e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -88,6 +88,49 @@ fn consts() {
}
#[test]
+fn enums() {
+ check_number(
+ r#"
+ enum E {
+ F1 = 1,
+ F2 = 2 * E::F1 as u8,
+ F3 = 3 * E::F2 as u8,
+ }
+ const GOAL: i32 = E::F3 as u8;
+ "#,
+ 6,
+ );
+ check_number(
+ r#"
+ enum E { F1 = 1, F2, }
+ const GOAL: i32 = E::F2 as u8;
+ "#,
+ 2,
+ );
+ check_number(
+ r#"
+ enum E { F1, }
+ const GOAL: i32 = E::F1 as u8;
+ "#,
+ 0,
+ );
+ let r = eval_goal(
+ r#"
+ enum E { A = 1, }
+ const GOAL: E = E::A;
+ "#,
+ )
+ .unwrap();
+ match r {
+ ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => {
+ assert_eq!(name, "E::A");
+ assert_eq!(val, 1);
+ }
+ x => panic!("Expected enum but found {:?}", x),
+ }
+}
+
+#[test]
fn const_loop() {
check_fail(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index b385b1caf..932fce835 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -6,8 +6,8 @@ use std::sync::Arc;
use arrayvec::ArrayVec;
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
use hir_def::{
- db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
- GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
+ db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
+ FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
};
use la_arena::ArenaMap;
@@ -43,10 +43,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::const_param_ty_query)]
fn const_param_ty(&self, def: ConstParamId) -> Ty;
- #[salsa::invoke(crate::consteval::const_eval_query)]
+ #[salsa::invoke(crate::consteval::const_eval_variant_query)]
#[salsa::cycle(crate::consteval::const_eval_recover)]
fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
+ #[salsa::invoke(crate::consteval::const_eval_query_variant)]
+ #[salsa::cycle(crate::consteval::const_eval_variant_recover)]
+ fn const_eval_variant(&self, def: EnumVariantId) -> Result<ComputedExpr, ConstEvalError>;
+
#[salsa::invoke(crate::lower::impl_trait_query)]
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
@@ -116,6 +120,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
#[salsa::interned]
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
+ #[salsa::interned]
+ fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;
#[salsa::invoke(chalk_db::associated_ty_data_query)]
fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
@@ -150,6 +156,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
id: chalk_db::AssociatedTyValueId,
) -> Arc<chalk_db::AssociatedTyValue>;
+ #[salsa::invoke(crate::traits::normalize_projection_query)]
+ #[salsa::transparent]
+ fn normalize_projection(
+ &self,
+ projection: crate::ProjectionTy,
+ env: Arc<crate::TraitEnvironment>,
+ ) -> Ty;
+
#[salsa::invoke(trait_solve_wait)]
#[salsa::transparent]
fn trait_solve(
@@ -180,6 +194,9 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
DefWithBodyId::ConstId(it) => {
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
}
+ DefWithBodyId::VariantId(it) => {
+ db.enum_data(it.parent).variants[it.local_id].name.to_string()
+ }
});
db.infer_query(def)
}
@@ -218,6 +235,10 @@ impl_intern_key!(InternedOpaqueTyId);
pub struct InternedClosureId(salsa::InternId);
impl_intern_key!(InternedClosureId);
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct InternedGeneratorId(salsa::InternId);
+impl_intern_key!(InternedGeneratorId);
+
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
/// we have different IDs for struct and enum variant constructors.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 161b19a73..431ab949b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -18,7 +18,9 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
let is_unsafe = match def {
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
- DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
+ DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => {
+ false
+ }
};
if is_unsafe {
return res;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index d2f9c2b8b..0221f922f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -20,13 +20,14 @@ use hir_def::{
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
+use smallvec::SmallVec;
use syntax::SmolStr;
use crate::{
db::HirDatabase,
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
mapping::from_chalk,
- primitive, subst_prefix, to_assoc_type_id,
+ primitive, to_assoc_type_id,
utils::{self, generics},
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
@@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
PathNotFound,
UnknownType,
Closure,
+ Generator,
}
pub enum HirDisplayError {
@@ -289,7 +291,7 @@ impl HirDisplay for ProjectionTy {
let trait_ = f.db.trait_data(self.trait_(f.db));
write!(f, "<")?;
- self.self_type_parameter(Interner).hir_fmt(f)?;
+ self.self_type_parameter(f.db).hir_fmt(f)?;
write!(f, " as {}", trait_.name)?;
if self.substitution.len(Interner) > 1 {
write!(f, "<")?;
@@ -504,8 +506,15 @@ impl HirDisplay for Ty {
let total_len = parent_params + self_param + type_params + const_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 {
+ // `parameters` are in the order of fn's params (including impl traits),
+ // parent's params (those from enclosing impl or trait, if any).
+ let parameters = parameters.as_slice(Interner);
+ let fn_params_len = self_param + type_params + const_params;
+ let fn_params = parameters.get(..fn_params_len);
+ let parent_params = parameters.get(parameters.len() - parent_params..);
+ let params = parent_params.into_iter().chain(fn_params).flatten();
write!(f, "<")?;
- f.write_joined(&parameters.as_slice(Interner)[..total_len], ", ")?;
+ f.write_joined(params, ", ")?;
write!(f, ">")?;
}
}
@@ -533,6 +542,7 @@ impl HirDisplay for Ty {
f.db.upcast(),
ItemInNs::Types((*def_id).into()),
module_id,
+ false,
) {
write!(f, "{}", path)?;
} else {
@@ -576,9 +586,8 @@ impl HirDisplay for Ty {
Some(x) => x,
None => return true,
};
- let actual_default = default_parameter
- .clone()
- .substitute(Interner, &subst_prefix(parameters, i));
+ let actual_default =
+ default_parameter.clone().substitute(Interner, &parameters);
parameter != &actual_default
}
let mut default_from = 0;
@@ -722,7 +731,7 @@ impl HirDisplay for Ty {
WhereClause::AliasEq(AliasEq {
alias: AliasTy::Projection(proj),
ty: _,
- }) => &proj.self_type_parameter(Interner) == self,
+ }) => &proj.self_type_parameter(f.db) == self,
_ => false,
})
.collect::<Vec<_>>();
@@ -742,9 +751,19 @@ impl HirDisplay for Ty {
}
TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
TyKind::Dyn(dyn_ty) => {
+ // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
+ // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
+ // more efficient when either of them hits stable.
+ let mut bounds: SmallVec<[_; 4]> =
+ dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
+ let (auto_traits, others): (SmallVec<[_; 4]>, _) =
+ bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
+ bounds.extend(others);
+ bounds.extend(auto_traits);
+
write_bounds_like_dyn_trait_with_prefix(
"dyn",
- dyn_ty.bounds.skip_binders().interned(),
+ &bounds,
SizedByDefault::NotSized,
f,
)?;
@@ -782,7 +801,34 @@ impl HirDisplay for Ty {
write!(f, "{{unknown}}")?;
}
TyKind::InferenceVar(..) => write!(f, "_")?,
- TyKind::Generator(..) => write!(f, "{{generator}}")?,
+ TyKind::Generator(_, subst) => {
+ if f.display_target.is_source_code() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::Generator,
+ ));
+ }
+
+ let subst = subst.as_slice(Interner);
+ let a: Option<SmallVec<[&Ty; 3]>> = subst
+ .get(subst.len() - 3..)
+ .map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
+ .flatten();
+
+ if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
+ write!(f, "|")?;
+ resume_ty.hir_fmt(f)?;
+ write!(f, "|")?;
+
+ write!(f, " yields ")?;
+ yield_ty.hir_fmt(f)?;
+
+ write!(f, " -> ")?;
+ ret_ty.hir_fmt(f)?;
+ } else {
+ // This *should* be unreachable, but fallback just in case.
+ write!(f, "{{generator}}")?;
+ }
+ }
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
}
Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 10ffde87e..0efff651c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -2,7 +2,7 @@
//! the type of each expression and pattern.
//!
//! For type inference, compare the implementations in rustc (the various
-//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
+//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
//! inference here is the `infer` function, which infers the types of all
//! expressions in a given function.
@@ -19,14 +19,15 @@ use std::sync::Arc;
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use hir_def::{
body::Body,
+ builtin_type::BuiltinType,
data::{ConstData, StaticData},
expr::{BindingAnnotation, ExprId, PatId},
lang_item::LangItemTarget,
path::{path, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::TypeRef,
- AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
- TraitId, TypeAliasId, VariantId,
+ AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
+ ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
};
use hir_expand::name::{name, Name};
use itertools::Either;
@@ -67,6 +68,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
+ DefWithBodyId::VariantId(v) => {
+ ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
+ Either::Left(builtin) => BuiltinType::Int(builtin),
+ Either::Right(builtin) => BuiltinType::Uint(builtin),
+ });
+ }
}
ctx.infer_body();
@@ -332,7 +339,7 @@ pub struct InferenceResult {
/// unresolved or missing subpatterns or subpatterns of mismatched types.
pub type_of_pat: ArenaMap<PatId, Ty>,
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
- /// Interned Unknown to return references to.
+ /// Interned common types to return references to.
standard_types: InternedStandardTypes,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
@@ -412,6 +419,8 @@ pub(crate) struct InferenceContext<'a> {
/// closures, but currently this is the only field that will change there,
/// so it doesn't make sense.
return_ty: Ty,
+ /// The resume type and the yield type, respectively, of the generator being inferred.
+ resume_yield_tys: Option<(Ty, Ty)>,
diverges: Diverges,
breakables: Vec<BreakableContext>,
}
@@ -476,6 +485,7 @@ impl<'a> InferenceContext<'a> {
table: unify::InferenceTable::new(db, trait_env.clone()),
trait_env,
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
+ resume_yield_tys: None,
db,
owner,
body,
@@ -673,10 +683,6 @@ impl<'a> InferenceContext<'a> {
)
}
- fn resolve_obligations_as_possible(&mut self) {
- self.table.resolve_obligations_as_possible();
- }
-
fn push_obligation(&mut self, o: DomainGoal) {
self.table.register_obligation(o.cast(Interner));
}
@@ -696,7 +702,6 @@ impl<'a> InferenceContext<'a> {
}
fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
- self.resolve_obligations_as_possible();
self.table.resolve_ty_shallow(ty)
}
@@ -708,6 +713,8 @@ impl<'a> InferenceContext<'a> {
&mut self,
inner_ty: Ty,
assoc_ty: Option<TypeAliasId>,
+ // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
+ // handled when we support them.
params: &[GenericArg],
) -> Ty {
match assoc_ty {
@@ -799,7 +806,18 @@ impl<'a> InferenceContext<'a> {
self.resolve_variant_on_alias(ty, unresolved, path)
}
TypeNs::TypeAliasId(it) => {
- let ty = TyBuilder::def_ty(self.db, it.into())
+ let container = it.lookup(self.db.upcast()).container;
+ let parent_subst = match container {
+ ItemContainerId::TraitId(id) => {
+ let subst = TyBuilder::subst_for_def(self.db, id, None)
+ .fill_with_inference_vars(&mut self.table)
+ .build();
+ Some(subst)
+ }
+ // Type aliases do not exist in impls.
+ _ => None,
+ };
+ let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
.fill_with_inference_vars(&mut self.table)
.build();
self.resolve_variant_on_alias(ty, unresolved, path)
@@ -878,6 +896,12 @@ impl<'a> InferenceContext<'a> {
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
let path = path![core::iter::IntoIterator];
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
+ self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
+ }
+
+ fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
+ let path = path![core::iter::Iterator];
+ let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 3ead92909..094e460db 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -12,6 +12,7 @@ use crate::{
use super::{Expectation, InferenceContext};
impl InferenceContext<'_> {
+ // This function handles both closures and generators.
pub(super) fn deduce_closure_type_from_expectations(
&mut self,
closure_expr: ExprId,
@@ -27,6 +28,11 @@ impl InferenceContext<'_> {
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
+ // Generators are not Fn* so return early.
+ if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) {
+ return;
+ }
+
// Deduction based on the expected `dyn Fn` is done separately.
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index f54440bf5..8df25c83c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -3,7 +3,7 @@
//! like going from `&Vec<T>` to `&[T]`.
//!
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
-//! `librustc_typeck/check/coercion.rs`.
+//! `rustc_hir_analysis/check/coercion.rs`.
use std::{iter, sync::Arc};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 2d04a864a..f56108b26 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -10,7 +10,10 @@ use chalk_ir::{
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
};
use hir_def::{
- expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
+ expr::{
+ ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
+ UnaryOp,
+ },
generics::TypeOrConstParamData,
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
@@ -204,8 +207,10 @@ impl<'a> InferenceContext<'a> {
}
&Expr::For { iterable, body, pat, label } => {
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
- let pat_ty =
+ let into_iter_ty =
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
+ let pat_ty =
+ self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
self.infer_pat(pat, &pat_ty, BindingMode::default());
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
@@ -216,7 +221,7 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe;
TyBuilder::unit()
}
- Expr::Closure { body, args, ret_type, arg_types } => {
+ Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
assert_eq!(args.len(), arg_types.len());
let mut sig_tys = Vec::new();
@@ -244,20 +249,40 @@ impl<'a> InferenceContext<'a> {
),
})
.intern(Interner);
- let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
- let closure_ty =
- TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
- .intern(Interner);
+
+ let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
+ // FIXME: report error when there are more than 1 parameter.
+ let resume_ty = match sig_tys.first() {
+ // When `sig_tys.len() == 1` the first type is the return type, not the
+ // first parameter type.
+ Some(ty) if sig_tys.len() > 1 => ty.clone(),
+ _ => self.result.standard_types.unit.clone(),
+ };
+ let yield_ty = self.table.new_type_var();
+
+ let subst = TyBuilder::subst_for_generator(self.db, self.owner)
+ .push(resume_ty.clone())
+ .push(yield_ty.clone())
+ .push(ret_ty.clone())
+ .build();
+
+ let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
+ let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
+
+ (generator_ty, Some((resume_ty, yield_ty)))
+ } else {
+ let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
+ let closure_ty =
+ TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
+ .intern(Interner);
+
+ (closure_ty, None)
+ };
// Eagerly try to relate the closure type with the expected
// type, otherwise we often won't have enough information to
// infer the body.
- self.deduce_closure_type_from_expectations(
- tgt_expr,
- &closure_ty,
- &sig_ty,
- expected,
- );
+ self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
// Now go through the argument patterns
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
@@ -266,6 +291,8 @@ impl<'a> InferenceContext<'a> {
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
+ let prev_resume_yield_tys =
+ mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
@@ -273,8 +300,9 @@ impl<'a> InferenceContext<'a> {
self.diverges = prev_diverges;
self.return_ty = prev_ret_ty;
+ self.resume_yield_tys = prev_resume_yield_tys;
- closure_ty
+ ty
}
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
@@ -423,11 +451,18 @@ impl<'a> InferenceContext<'a> {
TyKind::Never.intern(Interner)
}
Expr::Yield { expr } => {
- // FIXME: track yield type for coercion
- if let Some(expr) = expr {
- self.infer_expr(*expr, &Expectation::none());
+ if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
+ if let Some(expr) = expr {
+ self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
+ } else {
+ let unit = self.result.standard_types.unit.clone();
+ let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
+ }
+ resume_ty
+ } else {
+ // FIXME: report error (yield expr in non-generator)
+ TyKind::Error.intern(Interner)
}
- TyKind::Never.intern(Interner)
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
@@ -952,11 +987,13 @@ impl<'a> InferenceContext<'a> {
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
let rhs_ty = self.table.new_type_var();
- let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
- self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
+ let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+ let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
+ let func = self.db.trait_data(trait_id).method_by_name(&name)?;
+ Some((trait_id, func))
});
- let func = match func {
- Some(func) => func,
+ let (trait_, func) = match trait_func {
+ Some(it) => it,
None => {
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
@@ -966,7 +1003,9 @@ impl<'a> InferenceContext<'a> {
}
};
- let subst = TyBuilder::subst_for_def(self.db, func)
+ // HACK: We can use this substitution for the function because the function itself doesn't
+ // have its own generic parameters.
+ let subst = TyBuilder::subst_for_def(self.db, trait_, None)
.push(lhs_ty.clone())
.push(rhs_ty.clone())
.build();
@@ -1245,19 +1284,7 @@ impl<'a> InferenceContext<'a> {
assert_eq!(self_params, 0); // method shouldn't have another Self param
let total_len = parent_params + type_params + const_params + impl_trait_params;
let mut substs = Vec::with_capacity(total_len);
- // Parent arguments are unknown
- for (id, param) in def_generics.iter_parent() {
- match param {
- TypeOrConstParamData::TypeParamData(_) => {
- substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
- }
- TypeOrConstParamData::ConstParamData(_) => {
- let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
- substs
- .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
- }
- }
- }
+
// handle provided arguments
if let Some(generic_args) = generic_args {
// if args are provided, it should be all of them, but we can't rely on that
@@ -1266,7 +1293,7 @@ impl<'a> InferenceContext<'a> {
.iter()
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.take(type_params + const_params)
- .zip(def_generics.iter_id().skip(parent_params))
+ .zip(def_generics.iter_id())
{
if let Some(g) = generic_arg_to_chalk(
self.db,
@@ -1290,6 +1317,9 @@ impl<'a> InferenceContext<'a> {
}
}
};
+
+ // Handle everything else as unknown. This also handles generic arguments for the method's
+ // parent (impl or trait), which should come after those for the method.
for (id, data) in def_generics.iter().skip(substs.len()) {
match data {
TypeOrConstParamData::TypeParamData(_) => {
@@ -1327,9 +1357,13 @@ impl<'a> InferenceContext<'a> {
CallableDefId::FunctionId(f) => {
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
// construct a TraitRef
- let substs = crate::subst_prefix(
- &*parameters,
- generics(self.db.upcast(), trait_.into()).len(),
+ let params_len = parameters.len(Interner);
+ let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
+ let substs = Substitution::from_iter(
+ Interner,
+ // The generic parameters for the trait come after those for the
+ // function.
+ &parameters.as_slice(Interner)[params_len - trait_params_len..],
);
self.push_obligation(
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index f580e09e9..7a4754cdc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -12,8 +12,8 @@ use crate::{
builder::ParamKind,
consteval,
method_resolution::{self, VisibleFromModule},
- GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
- ValueTyDefId,
+ utils::generics,
+ Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
};
use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -96,17 +96,21 @@ impl<'a> InferenceContext<'a> {
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
};
- let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
let substs = ctx.substs_from_path(path, typable, true);
- let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
- let ty = TyBuilder::value_ty(self.db, typable)
- .use_parent_substs(&parent_substs)
+ let substs = substs.as_slice(Interner);
+ let parent_substs = self_subst.or_else(|| {
+ let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
+ let parent_params_len = generics.parent_generics()?.len();
+ let parent_args = &substs[substs.len() - parent_params_len..];
+ Some(Substitution::from_iter(Interner, parent_args))
+ });
+ let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
+ let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
+ let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
.fill(|x| {
it.next().unwrap_or_else(|| match x {
- ParamKind::Type => {
- GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
- }
+ ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
})
})
@@ -249,7 +253,7 @@ impl<'a> InferenceContext<'a> {
};
let substs = match container {
ItemContainerId::ImplId(impl_id) => {
- let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
+ let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
.fill_with_inference_vars(&mut self.table)
.build();
let impl_self_ty =
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index e77b55670..b00e3216b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
use chalk_ir::{
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
- IntTy, NoSolution, TyVariableKind, UniverseIndex,
+ IntTy, TyVariableKind, UniverseIndex,
};
use chalk_solve::infer::ParameterEnaVariableExt;
use ena::unify::UnifyKey;
@@ -331,7 +331,6 @@ impl<'a> InferenceTable<'a> {
&mut resolve::Resolver { table: self, var_stack, fallback },
DebruijnIndex::INNERMOST,
)
- .expect("fold failed unexpectedly")
}
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
@@ -452,13 +451,14 @@ impl<'a> InferenceTable<'a> {
f: impl FnOnce(&mut Self) -> T,
) -> T {
use chalk_ir::fold::TypeFolder;
+
+ #[derive(chalk_derive::FallibleTypeFolder)]
+ #[has_interner(Interner)]
struct VarFudger<'a, 'b> {
table: &'a mut InferenceTable<'b>,
highest_known_var: InferenceVar,
}
impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
- type Error = NoSolution;
-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
self
}
@@ -472,24 +472,24 @@ impl<'a> InferenceTable<'a> {
var: chalk_ir::InferenceVar,
kind: TyVariableKind,
_outer_binder: chalk_ir::DebruijnIndex,
- ) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
- Ok(if var < self.highest_known_var {
+ ) -> chalk_ir::Ty<Interner> {
+ if var < self.highest_known_var {
var.to_ty(Interner, kind)
} else {
self.table.new_type_var()
- })
+ }
}
fn fold_inference_lifetime(
&mut self,
var: chalk_ir::InferenceVar,
_outer_binder: chalk_ir::DebruijnIndex,
- ) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
- Ok(if var < self.highest_known_var {
+ ) -> chalk_ir::Lifetime<Interner> {
+ if var < self.highest_known_var {
var.to_lifetime(Interner)
} else {
self.table.new_lifetime_var()
- })
+ }
}
fn fold_inference_const(
@@ -497,12 +497,12 @@ impl<'a> InferenceTable<'a> {
ty: chalk_ir::Ty<Interner>,
var: chalk_ir::InferenceVar,
_outer_binder: chalk_ir::DebruijnIndex,
- ) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
- Ok(if var < self.highest_known_var {
+ ) -> chalk_ir::Const<Interner> {
+ if var < self.highest_known_var {
var.to_const(Interner, ty)
} else {
self.table.new_const_var(ty)
- })
+ }
}
}
@@ -512,7 +512,6 @@ impl<'a> InferenceTable<'a> {
self.rollback_to(snapshot);
result
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
- .expect("fold_with with VarFudger")
}
/// This checks whether any of the free variables in the `canonicalized`
@@ -598,11 +597,14 @@ impl<'a> InferenceTable<'a> {
.build();
let projection = {
- let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
+ let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
if b.remaining() != 2 {
return None;
}
- b.push(ty.clone()).push(arg_ty).build()
+ let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
+
+ TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
+ .build()
};
let trait_env = self.trait_env.env.clone();
@@ -636,21 +638,24 @@ mod resolve {
use chalk_ir::{
cast::Cast,
fold::{TypeFoldable, TypeFolder},
- Fallible, NoSolution,
};
use hir_def::type_ref::ConstScalar;
- pub(super) struct Resolver<'a, 'b, F> {
+ #[derive(chalk_derive::FallibleTypeFolder)]
+ #[has_interner(Interner)]
+ pub(super) struct Resolver<
+ 'a,
+ 'b,
+ F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+ > {
pub(super) table: &'a mut InferenceTable<'b>,
pub(super) var_stack: &'a mut Vec<InferenceVar>,
pub(super) fallback: F,
}
- impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
+ impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
where
- F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
+ F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
{
- type Error = NoSolution;
-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
self
}
@@ -664,20 +669,19 @@ mod resolve {
var: InferenceVar,
kind: TyVariableKind,
outer_binder: DebruijnIndex,
- ) -> Fallible<Ty> {
+ ) -> Ty {
let var = self.table.var_unification_table.inference_var_root(var);
if self.var_stack.contains(&var) {
// recursive type
let default = self.table.fallback_value(var, kind).cast(Interner);
- return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+ return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
.assert_ty_ref(Interner)
- .clone());
+ .clone();
}
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
// known_ty may contain other variables that are known by now
self.var_stack.push(var);
- let result =
- known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
+ let result = known_ty.fold_with(self, outer_binder);
self.var_stack.pop();
result.assert_ty_ref(Interner).clone()
} else {
@@ -686,7 +690,7 @@ mod resolve {
.assert_ty_ref(Interner)
.clone()
};
- Ok(result)
+ result
}
fn fold_inference_const(
@@ -694,7 +698,7 @@ mod resolve {
ty: Ty,
var: InferenceVar,
outer_binder: DebruijnIndex,
- ) -> Fallible<Const> {
+ ) -> Const {
let var = self.table.var_unification_table.inference_var_root(var);
let default = ConstData {
ty: ty.clone(),
@@ -704,35 +708,33 @@ mod resolve {
.cast(Interner);
if self.var_stack.contains(&var) {
// recursive
- return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+ return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
.assert_const_ref(Interner)
- .clone());
+ .clone();
}
- let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
+ if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
// known_ty may contain other variables that are known by now
self.var_stack.push(var);
- let result =
- known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
+ let result = known_ty.fold_with(self, outer_binder);
self.var_stack.pop();
result.assert_const_ref(Interner).clone()
} else {
(self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
.assert_const_ref(Interner)
.clone()
- };
- Ok(result)
+ }
}
fn fold_inference_lifetime(
&mut self,
_var: InferenceVar,
_outer_binder: DebruijnIndex,
- ) -> Fallible<Lifetime> {
+ ) -> Lifetime {
// fall back all lifetimes to 'static -- currently we don't deal
// with any lifetimes, but we can sometimes get some lifetime
// variables through Chalk's unification, and this at least makes
// sure we don't leak them outside of inference
- Ok(crate::static_lifetime())
+ crate::static_lifetime()
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index a82a331d4..c4b700cbc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -196,20 +196,6 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
make_binders_with_count(db, usize::MAX, generics, value)
}
-// FIXME: get rid of this
-pub fn make_canonical<T: HasInterner<Interner = Interner>>(
- value: T,
- kinds: impl IntoIterator<Item = TyVariableKind>,
-) -> Canonical<T> {
- let kinds = kinds.into_iter().map(|tk| {
- chalk_ir::CanonicalVarKind::new(
- chalk_ir::VariableKind::Ty(tk),
- chalk_ir::UniverseIndex::ROOT,
- )
- });
- Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
-}
-
// FIXME: get rid of this, just replace it by FnPointer
/// A function signature as seen by type inference: Several parameter types and
/// one return type.
@@ -268,13 +254,13 @@ impl CallableSig {
}
impl TypeFoldable<Interner> for CallableSig {
- fn fold_with<E>(
+ fn try_fold_with<E>(
self,
- folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
+ folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
outer_binder: DebruijnIndex,
) -> Result<Self, E> {
let vec = self.params_and_return.to_vec();
- let folded = vec.fold_with(folder, outer_binder)?;
+ let folded = vec.try_fold_with(folder, outer_binder)?;
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
}
}
@@ -306,16 +292,19 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
) -> T {
- use chalk_ir::{fold::TypeFolder, Fallible};
- struct FreeVarFolder<F1, F2>(F1, F2);
+ use chalk_ir::fold::TypeFolder;
+
+ #[derive(chalk_derive::FallibleTypeFolder)]
+ #[has_interner(Interner)]
+ struct FreeVarFolder<
+ F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
+ F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
+ >(F1, F2);
impl<
- 'i,
- F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
- F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
+ F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
+ F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
> TypeFolder<Interner> for FreeVarFolder<F1, F2>
{
- type Error = NoSolution;
-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
self
}
@@ -324,12 +313,8 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
Interner
}
- fn fold_free_var_ty(
- &mut self,
- bound_var: BoundVar,
- outer_binder: DebruijnIndex,
- ) -> Fallible<Ty> {
- Ok(self.0(bound_var, outer_binder))
+ fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
+ self.0(bound_var, outer_binder)
}
fn fold_free_var_const(
@@ -337,12 +322,11 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
ty: Ty,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
- ) -> Fallible<Const> {
- Ok(self.1(ty, bound_var, outer_binder))
+ ) -> Const {
+ self.1(ty, bound_var, outer_binder)
}
}
t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
- .expect("fold failed unexpectedly")
}
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
@@ -365,16 +349,13 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
binders: DebruijnIndex,
) -> T {
- use chalk_ir::{
- fold::{TypeFolder, TypeSuperFoldable},
- Fallible,
- };
- struct TyFolder<F>(F);
- impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
- TypeFolder<Interner> for TyFolder<F>
+ use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
+ #[derive(chalk_derive::FallibleTypeFolder)]
+ #[has_interner(Interner)]
+ struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
+ impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
+ for TyFolder<F>
{
- type Error = NoSolution;
-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
self
}
@@ -383,16 +364,16 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
Interner
}
- fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
- let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
- Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
+ fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
+ let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
+ self.0(Either::Left(ty), outer_binder).left().unwrap()
}
- fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
- Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
+ fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
+ self.0(Either::Right(c), outer_binder).right().unwrap()
}
}
- t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
+ t.fold_with(&mut TyFolder(f), binders)
}
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
@@ -404,16 +385,16 @@ where
T: HasInterner<Interner = Interner>,
{
use chalk_ir::{
- fold::{TypeFolder, TypeSuperFoldable},
+ fold::{FallibleTypeFolder, TypeSuperFoldable},
Fallible,
};
struct ErrorReplacer {
vars: usize,
}
- impl TypeFolder<Interner> for ErrorReplacer {
+ impl FallibleTypeFolder<Interner> for ErrorReplacer {
type Error = NoSolution;
- fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
+ fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
self
}
@@ -421,18 +402,17 @@ where
Interner
}
- fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
+ fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
if let TyKind::Error = ty.kind(Interner) {
let index = self.vars;
self.vars += 1;
Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
} else {
- let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
- Ok(ty)
+ ty.try_super_fold_with(self.as_dyn(), outer_binder)
}
}
- fn fold_inference_ty(
+ fn try_fold_inference_ty(
&mut self,
_var: InferenceVar,
_kind: TyVariableKind,
@@ -447,7 +427,7 @@ where
}
}
- fn fold_free_var_ty(
+ fn try_fold_free_var_ty(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
@@ -461,7 +441,7 @@ where
}
}
- fn fold_inference_const(
+ fn try_fold_inference_const(
&mut self,
ty: Ty,
_var: InferenceVar,
@@ -474,7 +454,7 @@ where
}
}
- fn fold_free_var_const(
+ fn try_fold_free_var_const(
&mut self,
ty: Ty,
_bound_var: BoundVar,
@@ -487,7 +467,7 @@ where
}
}
- fn fold_inference_lifetime(
+ fn try_fold_inference_lifetime(
&mut self,
_var: InferenceVar,
_outer_binder: DebruijnIndex,
@@ -499,7 +479,7 @@ where
}
}
- fn fold_free_var_lifetime(
+ fn try_fold_free_var_lifetime(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
@@ -512,7 +492,7 @@ where
}
}
let mut error_replacer = ErrorReplacer { vars: 0 };
- let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
+ let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
Ok(t) => t,
Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 532544fee..223d705b1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
// FIXME we're probably doing something wrong here
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
let (
- parent_params,
+ _parent_params,
self_params,
list_params,
const_params,
@@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
};
TyKind::BoundVar(BoundVar::new(
self.in_binders,
- idx as usize + parent_params + self_params + list_params + const_params,
+ idx as usize + self_params + list_params + const_params,
))
.intern(Interner)
}
@@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner)
}
TypeNs::SelfType(impl_id) => {
- let generics = generics(self.db.upcast(), impl_id.into());
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
+ let def =
+ self.resolver.generic_def().expect("impl should have generic param scope");
+ let generics = generics(self.db.upcast(), def);
+
+ match self.type_param_mode {
+ ParamLoweringMode::Placeholder => {
+ // `def` can be either impl itself or item within, and we need impl itself
+ // now.
+ let generics = generics.parent_generics().unwrap_or(&generics);
+ let subst = generics.placeholder_subst(self.db);
+ self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+ }
ParamLoweringMode::Variable => {
- generics.bound_vars_subst(self.db, self.in_binders)
+ let starting_from = match def {
+ GenericDefId::ImplId(_) => 0,
+ // `def` is an item within impl. We need to substitute `BoundVar`s but
+ // remember that they are for parent (i.e. impl) generic params so they
+ // come after our own params.
+ _ => generics.len_self(),
+ };
+ TyBuilder::impl_self_ty(self.db, impl_id)
+ .fill_with_bound_vars(self.in_binders, starting_from)
+ .build()
}
- };
- self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
+ }
}
TypeNs::AdtSelfType(adt) => {
let generics = generics(self.db.upcast(), adt.into());
@@ -663,40 +680,31 @@ impl<'a> TyLoweringContext<'a> {
fn substs_from_path_segment(
&self,
segment: PathSegment<'_>,
- def_generic: Option<GenericDefId>,
+ def: Option<GenericDefId>,
infer_args: bool,
explicit_self_ty: Option<Ty>,
) -> Substitution {
+ // Remember that the item's own generic args come before its parent's.
let mut substs = Vec::new();
- let def_generics = if let Some(def) = def_generic {
- generics(self.db.upcast(), def)
+ let def = if let Some(d) = def {
+ d
} else {
return Substitution::empty(Interner);
};
+ let def_generics = generics(self.db.upcast(), def);
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
def_generics.provenance_split();
- let total_len =
- parent_params + self_params + type_params + const_params + impl_trait_params;
+ let item_len = self_params + type_params + const_params + impl_trait_params;
+ let total_len = parent_params + item_len;
- let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
+ let ty_error = TyKind::Error.intern(Interner).cast(Interner);
let mut def_generic_iter = def_generics.iter_id();
- for _ in 0..parent_params {
- if let Some(eid) = def_generic_iter.next() {
- match eid {
- Either::Left(_) => substs.push(ty_error.clone()),
- Either::Right(x) => {
- substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
- }
- }
- }
- }
-
let fill_self_params = || {
for x in explicit_self_ty
.into_iter()
- .map(|x| GenericArgData::Ty(x).intern(Interner))
+ .map(|x| x.cast(Interner))
.chain(iter::repeat(ty_error.clone()))
.take(self_params)
{
@@ -757,37 +765,40 @@ impl<'a> TyLoweringContext<'a> {
fill_self_params();
}
+ // These params include those of parent.
+ let remaining_params: SmallVec<[_; 2]> = def_generic_iter
+ .map(|eid| match eid {
+ Either::Left(_) => ty_error.clone(),
+ Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
+ })
+ .collect();
+ assert_eq!(remaining_params.len() + substs.len(), total_len);
+
// handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used).
if !infer_args || had_explicit_args {
- if let Some(def_generic) = def_generic {
- let defaults = self.db.generic_defaults(def_generic);
- assert_eq!(total_len, defaults.len());
-
- for default_ty in defaults.iter().skip(substs.len()) {
- // each default can depend on the previous parameters
- let substs_so_far = Substitution::from_iter(Interner, substs.clone());
- if let Some(_id) = def_generic_iter.next() {
- substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
- }
- }
+ let defaults = self.db.generic_defaults(def);
+ assert_eq!(total_len, defaults.len());
+ let parent_from = item_len - substs.len();
+
+ for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
+ // each default can depend on the previous parameters
+ let substs_so_far = Substitution::from_iter(
+ Interner,
+ substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
+ );
+ substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
}
- }
- // add placeholders for args that were not provided
- // FIXME: emit diagnostics in contexts where this is not allowed
- for eid in def_generic_iter {
- match eid {
- Either::Left(_) => substs.push(ty_error.clone()),
- Either::Right(x) => {
- substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
- }
- }
+ // Keep parent's params as unknown.
+ let mut remaining_params = remaining_params;
+ substs.extend(remaining_params.drain(parent_from..));
+ } else {
+ substs.extend(remaining_params);
}
- // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
- assert_eq!(substs.len(), total_len);
+ assert_eq!(substs.len(), total_len);
Substitution::from_iter(Interner, substs)
}
@@ -981,10 +992,11 @@ impl<'a> TyLoweringContext<'a> {
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
- // INVARIANT: The principal trait bound must come first. Others may be in any order but
- // should be in the same order for the same set but possibly different order of bounds in
- // the input.
- // This invariant is used by `TyExt::dyn_trait()` and chalk.
+ // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
+ // order but should be in the same order for the same set but possibly different order of
+ // bounds in the input.
+ // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
+ // These invariants are utilized by `TyExt::dyn_trait()` and chalk.
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
let mut bounds: Vec<_> = bounds
.iter()
@@ -1035,6 +1047,12 @@ impl<'a> TyLoweringContext<'a> {
return None;
}
+ if bounds.first().and_then(|b| b.trait_id()).is_none() {
+ // When there's no trait bound, that's an error. This happens when the trait refs
+ // are unresolved.
+ return None;
+ }
+
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
// bounds. We shouldn't have repeated elements besides auto traits at this point.
bounds.dedup();
@@ -1046,7 +1064,8 @@ impl<'a> TyLoweringContext<'a> {
let bounds = crate::make_single_type_binders(bounds);
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
} else {
- // FIXME: report error (additional non-auto traits or associated type rebound)
+ // FIXME: report error
+ // (additional non-auto traits, associated type rebound, or no resolved trait)
TyKind::Error.intern(Interner)
}
}
@@ -1139,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
};
match res {
- TypeNs::SelfType(impl_id) => search(
+ TypeNs::SelfType(impl_id) => {
// we're _in_ the impl -- the binders get added back later. Correct,
// but it would be nice to make this more explicit
- db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
- ),
+ let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+
+ let impl_id_as_generic_def: GenericDefId = impl_id.into();
+ if impl_id_as_generic_def != def {
+ // `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
+ // `BoundVar`s from `def`'s point of view.
+ // FIXME: A `HirDatabase` query may be handy if this process is needed in more
+ // places. It'd be almost identical as `impl_trait_query` where `resolver` would be
+ // of `def` instead of `impl_id`.
+ let starting_idx = generics(db.upcast(), def).len_self();
+ let subst = TyBuilder::subst_for_def(db, impl_id, None)
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
+ .build();
+ let trait_ref = subst.apply(trait_ref, Interner);
+ search(trait_ref)
+ } else {
+ search(trait_ref)
+ }
+ }
TypeNs::GenericParam(param_id) => {
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
@@ -1160,10 +1196,18 @@ fn named_associated_type_shorthand_candidates<R>(
}
// Handle `Self::Type` referring to own associated type in trait definitions
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let generics = generics(db.upcast(), trait_id.into());
- if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+ let trait_generics = generics(db.upcast(), trait_id.into());
+ if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+ let def_generics = generics(db.upcast(), def);
+ let starting_idx = match def {
+ GenericDefId::TraitId(_) => 0,
+ // `def` is an item within trait. We need to substitute `BoundVar`s but
+ // remember that they are for parent (i.e. trait) generic params so they
+ // come after our own params.
+ _ => def_generics.len_self(),
+ };
let trait_ref = TyBuilder::trait_ref(db, trait_id)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
.build();
return search(trait_ref);
}
@@ -1405,6 +1449,7 @@ pub(crate) fn generic_defaults_query(
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let generic_params = generics(db.upcast(), def);
+ let parent_start_idx = generic_params.len_self();
let defaults = generic_params
.iter()
@@ -1417,19 +1462,17 @@ pub(crate) fn generic_defaults_query(
let val = unknown_const_as_generic(
db.const_param_ty(ConstParamId::from_unchecked(id)),
);
- return crate::make_binders_with_count(db, idx, &generic_params, val);
+ return make_binders(db, &generic_params, val);
}
};
let mut ty =
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters.
- // type variable default referring to parameter coming
- // after it. This is forbidden (FIXME: report
- // diagnostic)
- ty = fallback_bound_vars(ty, idx);
- let val = GenericArgData::Ty(ty).intern(Interner);
- crate::make_binders_with_count(db, idx, &generic_params, val)
+ // Type variable default referring to parameter coming
+ // after it is forbidden (FIXME: report diagnostic)
+ ty = fallback_bound_vars(ty, idx, parent_start_idx);
+ crate::make_binders(db, &generic_params, ty.cast(Interner))
})
.collect();
@@ -1446,15 +1489,14 @@ pub(crate) fn generic_defaults_recover(
// we still need one default per parameter
let defaults = generic_params
.iter_id()
- .enumerate()
- .map(|(count, id)| {
+ .map(|id| {
let val = match id {
itertools::Either::Left(_) => {
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
}
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
};
- crate::make_binders_with_count(db, count, &generic_params, val)
+ crate::make_binders(db, &generic_params, val)
})
.collect();
@@ -1633,6 +1675,19 @@ pub enum ValueTyDefId {
}
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
+impl ValueTyDefId {
+ pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
+ match self {
+ Self::FunctionId(id) => Some(id.into()),
+ Self::StructId(id) => Some(id.into()),
+ Self::UnionId(id) => Some(id.into()),
+ Self::EnumVariantId(var) => Some(var.into()),
+ Self::ConstId(id) => Some(id.into()),
+ Self::StaticId(_) => None,
+ }
+ }
+}
+
/// Build the declared type of an item. This depends on the namespace; e.g. for
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
/// the constructor function `(usize) -> Foo` which lives in the values
@@ -1816,26 +1871,48 @@ pub(crate) fn const_or_path_to_chalk(
}
}
-/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
-/// num_vars_to_keep) by `TyKind::Unknown`.
+/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
+/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
+/// appears after the generic parameter of `param_index`.
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
s: T,
- num_vars_to_keep: usize,
+ param_index: usize,
+ parent_start: usize,
) -> T {
+ // Keep in mind that parent generic parameters, if any, come *after* those of the item in
+ // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
+ // its parent respectively.
+ let is_allowed = |index| {
+ if param_index < parent_start {
+ // The parameter of `param_index` is one from the item in question. Any parent generic
+ // parameters or the item's generic parameters that come before `param_index` is
+ // allowed.
+ // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
+ // ^^^^^^ ^^^^^^^^^^ these are allowed
+ !(param_index..parent_start).contains(&index)
+ } else {
+ // The parameter of `param_index` is one from the parent generics. Only parent generic
+ // parameters that come before `param_index` are allowed.
+ // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
+ // ^^^^^^ these are allowed
+ (parent_start..param_index).contains(&index)
+ }
+ };
+
crate::fold_free_vars(
s,
|bound, binders| {
- if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
- TyKind::Error.intern(Interner)
- } else {
+ if bound.index_if_innermost().map_or(true, is_allowed) {
bound.shifted_in_from(binders).to_ty(Interner)
+ } else {
+ TyKind::Error.intern(Interner)
}
},
|ty, bound, binders| {
- if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
- unknown_const(ty.clone())
- } else {
+ if bound.index_if_innermost().map_or(true, is_allowed) {
bound.shifted_in_from(binders).to_const(Interner, ty)
+ } else {
+ unknown_const(ty.clone())
}
},
)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
index d765fee0e..f80fb39c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
@@ -103,6 +103,18 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
}
}
+impl From<chalk_ir::GeneratorId<Interner>> for crate::db::InternedGeneratorId {
+ fn from(id: chalk_ir::GeneratorId<Interner>) -> Self {
+ Self::from_intern_id(id.0)
+ }
+}
+
+impl From<crate::db::InternedGeneratorId> for chalk_ir::GeneratorId<Interner> {
+ fn from(id: crate::db::InternedGeneratorId) -> Self {
+ chalk_ir::GeneratorId(id.as_intern_id())
+ }
+}
+
pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 9a63d5013..3a1a3f4fd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -1,7 +1,7 @@
//! This module is concerned with finding methods that a given type provides.
//! For details about how this works in rustc, see the method lookup page in the
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
-//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
+//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
use std::{iter, ops::ControlFlow, sync::Arc};
use arrayvec::ArrayVec;
@@ -654,7 +654,7 @@ fn find_matching_impl(
let r = table.run_in_snapshot(|table| {
let impl_data = db.impl_data(impl_);
let substs =
- TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
+ TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
table
@@ -914,22 +914,10 @@ fn iterate_trait_method_candidates(
let db = table.db;
let env = table.trait_env.clone();
let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
- // if ty is `dyn Trait`, the trait doesn't need to be in scope
- let inherent_trait =
- self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
- let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
- // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
- .then(|| {
- env.traits_in_scope_from_clauses(self_ty.clone())
- .flat_map(|t| all_super_traits(db.upcast(), t))
- })
- .into_iter()
- .flatten();
- let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
- 'traits: for t in traits {
+ 'traits: for &t in traits_in_scope {
let data = db.trait_data(t);
// Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
@@ -979,6 +967,44 @@ fn iterate_inherent_methods(
) -> ControlFlow<()> {
let db = table.db;
let env = table.trait_env.clone();
+
+ // For trait object types and placeholder types with trait bounds, the methods of the trait and
+ // its super traits are considered inherent methods. This matters because these methods have
+ // higher priority than the other traits' methods, which would be considered in
+ // `iterate_trait_method_candidates()` only after this function.
+ match self_ty.kind(Interner) {
+ TyKind::Placeholder(_) => {
+ let env = table.trait_env.clone();
+ let traits = env
+ .traits_in_scope_from_clauses(self_ty.clone())
+ .flat_map(|t| all_super_traits(db.upcast(), t));
+ iterate_inherent_trait_methods(
+ self_ty,
+ table,
+ name,
+ receiver_ty,
+ receiver_adjustments.clone(),
+ callback,
+ traits,
+ )?;
+ }
+ TyKind::Dyn(_) => {
+ if let Some(principal_trait) = self_ty.dyn_trait() {
+ let traits = all_super_traits(db.upcast(), principal_trait);
+ iterate_inherent_trait_methods(
+ self_ty,
+ table,
+ name,
+ receiver_ty,
+ receiver_adjustments.clone(),
+ callback,
+ traits.into_iter(),
+ )?;
+ }
+ }
+ _ => {}
+ }
+
let def_crates = match def_crates(db, self_ty, env.krate) {
Some(k) => k,
None => return ControlFlow::Continue(()),
@@ -1020,6 +1046,28 @@ fn iterate_inherent_methods(
}
return ControlFlow::Continue(());
+ fn iterate_inherent_trait_methods(
+ self_ty: &Ty,
+ table: &mut InferenceTable<'_>,
+ name: Option<&Name>,
+ receiver_ty: Option<&Ty>,
+ receiver_adjustments: Option<ReceiverAdjustments>,
+ callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+ traits: impl Iterator<Item = TraitId>,
+ ) -> ControlFlow<()> {
+ let db = table.db;
+ for t in traits {
+ let data = db.trait_data(t);
+ for &(_, item) in data.items.iter() {
+ // We don't pass `visible_from_module` as all trait items should be visible.
+ if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+ callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+
fn impls_for_self_ty(
impls: &InherentImpls,
self_ty: &Ty,
@@ -1099,10 +1147,9 @@ fn is_valid_candidate(
}));
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
let self_ty_matches = table.run_in_snapshot(|table| {
- let subst =
- TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
- let expected_self_ty =
- subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
+ let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
+ .fill_with_inference_vars(table)
+ .build();
table.unify(&expected_self_ty, &self_ty)
});
if !self_ty_matches {
@@ -1138,31 +1185,26 @@ fn is_valid_fn_candidate(
table.run_in_snapshot(|table| {
let container = fn_id.lookup(db.upcast()).container;
- let impl_subst = match container {
+ let (impl_subst, expect_self_ty) = match container {
ItemContainerId::ImplId(it) => {
- TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+ let subst =
+ TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+ let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
+ (subst, self_ty)
}
ItemContainerId::TraitId(it) => {
- TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
+ let subst =
+ TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
+ let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
+ (subst, self_ty)
}
_ => unreachable!(),
};
- let fn_subst = TyBuilder::subst_for_def(db, fn_id)
- .use_parent_substs(&impl_subst)
+ let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
.fill_with_inference_vars(table)
.build();
- let expect_self_ty = match container {
- ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
- ItemContainerId::ImplId(impl_id) => {
- fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
- }
- // We should only get called for associated items (impl/trait)
- ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
- unreachable!()
- }
- };
check_that!(table.unify(&expect_self_ty, self_ty));
if let Some(receiver_ty) = receiver_ty {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index d2f13e435..ebbc54101 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -16,7 +16,7 @@ use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
use expect_test::Expect;
use hir_def::{
body::{Body, BodySourceMap, SyntheticSyntax},
- db::DefDatabase,
+ db::{DefDatabase, InternDatabase},
expr::{ExprId, PatId},
item_scope::ItemScope,
nameres::DefMap,
@@ -135,6 +135,10 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
let loc = it.lookup(&db);
loc.source(&db).value.syntax().text_range().start()
}
+ DefWithBodyId::VariantId(it) => {
+ let loc = db.lookup_intern_enum(it.parent);
+ loc.source(&db).value.syntax().text_range().start()
+ }
});
let mut unexpected_type_mismatches = String::new();
for def in defs {
@@ -388,6 +392,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let loc = it.lookup(&db);
loc.source(&db).value.syntax().text_range().start()
}
+ DefWithBodyId::VariantId(it) => {
+ let loc = db.lookup_intern_enum(it.parent);
+ loc.source(&db).value.syntax().text_range().start()
+ }
});
for def in defs {
let (_body, source_map) = db.body_with_source_map(def);
@@ -453,6 +461,18 @@ fn visit_module(
let body = db.body(def);
visit_body(db, &body, cb);
}
+ ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
+ db.enum_data(it)
+ .variants
+ .iter()
+ .map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
+ .for_each(|it| {
+ let def = it.into();
+ cb(def);
+ let body = db.body(def);
+ visit_body(db, &body, cb);
+ });
+ }
ModuleDefId::TraitId(it) => {
let trait_data = db.trait_data(it);
for &(_, item) in trait_data.items.iter() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index bf59fadc2..d301595bc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -295,6 +295,24 @@ fn foo() {
}
#[test]
+fn generator_yield_return_coerce() {
+ check_no_mismatches(
+ r#"
+fn test() {
+ let g = || {
+ yield &1u32;
+ yield &&1u32;
+ if true {
+ return &1u32;
+ }
+ &&1u32
+ };
+}
+ "#,
+ );
+}
+
+#[test]
fn assign_coerce() {
check_no_mismatches(
r"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index 240942e48..8a8ff08cf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -56,6 +56,28 @@ fn main() {
}
#[test]
+fn render_dyn_ty_independent_of_order() {
+ check_types_source_code(
+ r#"
+auto trait Send {}
+trait A {
+ type Assoc;
+}
+trait B: A {}
+
+fn test(
+ _: &(dyn A<Assoc = ()> + Send),
+ //^ &(dyn A<Assoc = ()> + Send)
+ _: &(dyn Send + A<Assoc = ()>),
+ //^ &(dyn A<Assoc = ()> + Send)
+ _: &dyn B<Assoc = ()>,
+ //^ &(dyn B<Assoc = ()>)
+) {}
+ "#,
+ );
+}
+
+#[test]
fn render_dyn_for_ty() {
// FIXME
check_types_source_code(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 81588a7c4..ac8edb841 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1219,6 +1219,40 @@ fn main() {
}
#[test]
+fn dyn_trait_method_priority() {
+ check_types(
+ r#"
+//- minicore: from
+trait Trait {
+ fn into(&self) -> usize { 0 }
+}
+
+fn foo(a: &dyn Trait) {
+ let _ = a.into();
+ //^usize
+}
+ "#,
+ );
+}
+
+#[test]
+fn trait_method_priority_for_placeholder_type() {
+ check_types(
+ r#"
+//- minicore: from
+trait Trait {
+ fn into(&self) -> usize { 0 }
+}
+
+fn foo<T: Trait>(a: &T) {
+ let _ = a.into();
+ //^usize
+}
+ "#,
+ );
+}
+
+#[test]
fn autoderef_visibility_field() {
check(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index eb04bf877..74de33117 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -1070,3 +1070,13 @@ fn main() {
"#,
);
}
+
+#[test]
+fn cfg_params() {
+ check_types(
+ r#"
+fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
+ //^^^ u32
+"#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 23e51a9c1..a155adcec 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -1488,7 +1488,6 @@ fn regression_11688_4() {
#[test]
fn gat_crash_1() {
- cov_mark::check!(ignore_gats);
check_no_mismatches(
r#"
trait ATrait {}
@@ -1527,30 +1526,22 @@ unsafe impl Storage for InlineStorage {
#[test]
fn gat_crash_3() {
- // FIXME: This test currently crashes rust analyzer in a debug build but not in a
- // release build (i.e. for the user). With the assumption that tests will always be run
- // in debug mode, we catch the unwind and expect that it panicked. See the
- // [`crate::utils::generics`] function for more information.
- cov_mark::check!(ignore_gats);
- std::panic::catch_unwind(|| {
- check_no_mismatches(
- r#"
+ check_no_mismatches(
+ r#"
trait Collection {
- type Item;
- type Member<T>: Collection<Item = T>;
- fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
+type Item;
+type Member<T>: Collection<Item = T>;
+fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
}
struct ConstGen<T, const N: usize> {
- data: [T; N],
+data: [T; N],
}
impl<T, const N: usize> Collection for ConstGen<T, N> {
- type Item = T;
- type Member<U> = ConstGen<U, N>;
+type Item = T;
+type Member<U> = ConstGen<U, N>;
}
- "#,
- );
- })
- .expect_err("must panic");
+ "#,
+ );
}
#[test]
@@ -1691,3 +1682,28 @@ fn macrostmts() -> u8 {
"#,
);
}
+
+#[test]
+fn dyn_with_unresolved_trait() {
+ check_types(
+ r#"
+fn foo(a: &dyn DoesNotExist) {
+ a.bar();
+ //^&{unknown}
+}
+ "#,
+ );
+}
+
+#[test]
+fn self_assoc_with_const_generics_crash() {
+ check_no_mismatches(
+ r#"
+trait Trait { type Item; }
+impl<T, const N: usize> Trait for [T; N] {
+ type Item = ();
+ fn f<U>(_: Self::Item) {}
+}
+ "#,
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 4ea103e5d..080e2ac1b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -1693,16 +1693,16 @@ fn infer_type_param() {
fn infer_const() {
check_infer(
r#"
- struct Foo;
- impl Foo { const ASSOC_CONST: u32 = 0; }
- const GLOBAL_CONST: u32 = 101;
- fn test() {
- const LOCAL_CONST: u32 = 99;
- let x = LOCAL_CONST;
- let z = GLOBAL_CONST;
- let id = Foo::ASSOC_CONST;
- }
- "#,
+struct Foo;
+impl Foo { const ASSOC_CONST: u32 = 0; }
+const GLOBAL_CONST: u32 = 101;
+fn test() {
+ const LOCAL_CONST: u32 = 99;
+ let x = LOCAL_CONST;
+ let z = GLOBAL_CONST;
+ let id = Foo::ASSOC_CONST;
+}
+"#,
expect![[r#"
48..49 '0': u32
79..82 '101': u32
@@ -1722,17 +1722,17 @@ fn infer_const() {
fn infer_static() {
check_infer(
r#"
- static GLOBAL_STATIC: u32 = 101;
- static mut GLOBAL_STATIC_MUT: u32 = 101;
- fn test() {
- static LOCAL_STATIC: u32 = 99;
- static mut LOCAL_STATIC_MUT: u32 = 99;
- let x = LOCAL_STATIC;
- let y = LOCAL_STATIC_MUT;
- let z = GLOBAL_STATIC;
- let w = GLOBAL_STATIC_MUT;
- }
- "#,
+static GLOBAL_STATIC: u32 = 101;
+static mut GLOBAL_STATIC_MUT: u32 = 101;
+fn test() {
+ static LOCAL_STATIC: u32 = 99;
+ static mut LOCAL_STATIC_MUT: u32 = 99;
+ let x = LOCAL_STATIC;
+ let y = LOCAL_STATIC_MUT;
+ let z = GLOBAL_STATIC;
+ let w = GLOBAL_STATIC_MUT;
+}
+"#,
expect![[r#"
28..31 '101': u32
69..72 '101': u32
@@ -1752,6 +1752,41 @@ fn infer_static() {
}
#[test]
+fn infer_enum_variant() {
+ check_infer(
+ r#"
+enum Foo {
+ A = 15,
+ B = Foo::A as isize + 1
+}
+"#,
+ expect![[r#"
+ 19..21 '15': isize
+ 31..37 'Foo::A': Foo
+ 31..46 'Foo::A as isize': isize
+ 31..50 'Foo::A...ze + 1': isize
+ 49..50 '1': isize
+ "#]],
+ );
+ check_infer(
+ r#"
+#[repr(u32)]
+enum Foo {
+ A = 15,
+ B = Foo::A as u32 + 1
+}
+"#,
+ expect![[r#"
+ 32..34 '15': u32
+ 44..50 'Foo::A': Foo
+ 44..57 'Foo::A as u32': u32
+ 44..61 'Foo::A...32 + 1': u32
+ 60..61 '1': u32
+ "#]],
+ );
+}
+
+#[test]
fn shadowing_primitive() {
check_types(
r#"
@@ -1918,6 +1953,88 @@ fn closure_return_inferred() {
}
#[test]
+fn generator_types_inferred() {
+ check_infer(
+ r#"
+//- minicore: generator, deref
+use core::ops::{Generator, GeneratorState};
+use core::pin::Pin;
+
+fn f(v: i64) {}
+fn test() {
+ let mut g = |r| {
+ let a = yield 0;
+ let a = yield 1;
+ let a = yield 2;
+ "return value"
+ };
+
+ match Pin::new(&mut g).resume(0usize) {
+ GeneratorState::Yielded(y) => { f(y); }
+ GeneratorState::Complete(r) => {}
+ }
+}
+ "#,
+ expect![[r#"
+ 70..71 'v': i64
+ 78..80 '{}': ()
+ 91..362 '{ ... } }': ()
+ 101..106 'mut g': |usize| yields i64 -> &str
+ 109..218 '|r| { ... }': |usize| yields i64 -> &str
+ 110..111 'r': usize
+ 113..218 '{ ... }': &str
+ 127..128 'a': usize
+ 131..138 'yield 0': usize
+ 137..138 '0': i64
+ 152..153 'a': usize
+ 156..163 'yield 1': usize
+ 162..163 '1': i64
+ 177..178 'a': usize
+ 181..188 'yield 2': usize
+ 187..188 '2': i64
+ 198..212 '"return value"': &str
+ 225..360 'match ... }': ()
+ 231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
+ 231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
+ 231..262 'Pin::n...usize)': GeneratorState<i64, &str>
+ 240..246 '&mut g': &mut |usize| yields i64 -> &str
+ 245..246 'g': |usize| yields i64 -> &str
+ 255..261 '0usize': usize
+ 273..299 'Genera...ded(y)': GeneratorState<i64, &str>
+ 297..298 'y': i64
+ 303..312 '{ f(y); }': ()
+ 305..306 'f': fn f(i64)
+ 305..309 'f(y)': ()
+ 307..308 'y': i64
+ 321..348 'Genera...ete(r)': GeneratorState<i64, &str>
+ 346..347 'r': &str
+ 352..354 '{}': ()
+ "#]],
+ );
+}
+
+#[test]
+fn generator_resume_yield_return_unit() {
+ check_no_mismatches(
+ r#"
+//- minicore: generator, deref
+use core::ops::{Generator, GeneratorState};
+use core::pin::Pin;
+fn test() {
+ let mut g = || {
+ let () = yield;
+ };
+
+ match Pin::new(&mut g).resume(()) {
+ GeneratorState::Yielded(()) => {}
+ GeneratorState::Complete(()) => {}
+ }
+}
+ "#,
+ );
+}
+
+#[test]
fn fn_pointer_return() {
check_infer(
r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 21a863197..555b6972f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -279,6 +279,10 @@ fn test() {
pub mod iter {
pub trait IntoIterator {
type Item;
+ type IntoIter: Iterator<Item = Self::Item>;
+ }
+ pub trait Iterator {
+ type Item;
}
}
pub mod prelude {
@@ -297,7 +301,13 @@ pub mod collections {
}
impl<T> IntoIterator for Vec<T> {
- type Item=T;
+ type Item = T;
+ type IntoIter = IntoIter<T>;
+ }
+
+ struct IntoIter<T> {}
+ impl<T> Iterator for IntoIter<T> {
+ type Item = T;
}
}
"#,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 77afeb321..c425f35ac 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -1,6 +1,6 @@
//! Trait solving using Chalk.
-use std::env::var;
+use std::{env::var, sync::Arc};
use chalk_ir::GoalData;
use chalk_recursive::Cache;
@@ -12,8 +12,9 @@ use stdx::panic_context;
use syntax::SmolStr;
use crate::{
- db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
- Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
+ db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
+ Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
+ TyKind, WhereClause,
};
/// This controls how much 'time' we give the Chalk solver before giving up.
@@ -64,6 +65,16 @@ impl TraitEnvironment {
}
}
+pub(crate) fn normalize_projection_query(
+ db: &dyn HirDatabase,
+ projection: ProjectionTy,
+ env: Arc<TraitEnvironment>,
+) -> Ty {
+ let mut table = InferenceTable::new(db, env);
+ let ty = table.normalize_projection_ty(projection);
+ table.resolve_completely(ty)
+}
+
/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
db: &dyn HirDatabase,
@@ -84,7 +95,7 @@ pub(crate) fn trait_solve_query(
..
}))) = &goal.value.goal.data(Interner)
{
- if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
+ if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
return Some(Solution::Ambig(Guidance::Unknown));
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index d6638db02..e54bcb421 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -4,7 +4,7 @@
use std::iter;
use base_db::CrateId;
-use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
+use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
use hir_def::{
db::DefDatabase,
generics::{
@@ -24,8 +24,7 @@ use smallvec::{smallvec, SmallVec};
use syntax::SmolStr;
use crate::{
- db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
- TraitRef, TraitRefExt, TyKind, WhereClause,
+ db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
};
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
@@ -174,31 +173,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
- if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
- let params = db.generic_params(def);
- let parent_params = &parent_generics.as_ref().unwrap().params;
- let has_consts =
- params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
- let parent_has_consts =
- parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
- return if has_consts || parent_has_consts {
- // XXX: treat const generic associated types as not existing to avoid crashes
- // (#11769)
- //
- // Note: Also crashes when the parent has const generics (also even if the GAT
- // doesn't use them), see `tests::regression::gat_crash_3` for an example.
- // Avoids that by disabling GATs when the parent (i.e. `impl` block) has
- // const generics (#12193).
- //
- // Chalk expects the inner associated type's parameters to come
- // *before*, not after the trait's generics as we've always done it.
- // Adapting to this requires a larger refactoring
- cov_mark::hit!(ignore_gats);
- Generics { def, params: Interned::new(Default::default()), parent_generics }
- } else {
- Generics { def, params, parent_generics }
- };
- }
Generics { def, params: db.generic_params(def), parent_generics }
}
@@ -221,23 +195,30 @@ impl Generics {
})
}
- /// Iterator over types and const params of parent, then self.
+ /// Iterator over types and const params of self, then parent.
pub(crate) fn iter<'a>(
&'a self,
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
let to_toc_id = |it: &'a Generics| {
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
};
- self.parent_generics()
- .into_iter()
- .flat_map(move |it| it.params.iter().map(to_toc_id(it)))
- .chain(self.params.iter().map(to_toc_id(self)))
+ self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
+ }
+
+ /// Iterate over types and const params without parent params.
+ pub(crate) fn iter_self<'a>(
+ &'a self,
+ ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+ let to_toc_id = |it: &'a Generics| {
+ move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
+ };
+ self.params.iter().map(to_toc_id(self))
}
/// Iterator over types and const params of parent.
pub(crate) fn iter_parent<'a>(
&'a self,
- ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+ ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
self.parent_generics().into_iter().flat_map(|it| {
let to_toc_id =
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
@@ -245,12 +226,18 @@ impl Generics {
})
}
+ /// Returns total number of generic parameters in scope, including those from parent.
pub(crate) fn len(&self) -> usize {
let parent = self.parent_generics().map_or(0, Generics::len);
let child = self.params.type_or_consts.len();
parent + child
}
+ /// Returns numbers of generic parameters excluding those from parent.
+ pub(crate) fn len_self(&self) -> usize {
+ self.params.type_or_consts.len()
+ }
+
/// (parent total, self param, type param list, const param list, impl trait)
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
@@ -275,15 +262,17 @@ impl Generics {
if param.parent == self.def {
let (idx, (_local_id, data)) =
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
- let parent_len = self.parent_generics().map_or(0, Generics::len);
- Some((parent_len + idx, data))
+ Some((idx, data))
} else {
- self.parent_generics().and_then(|g| g.find_param(param))
+ self.parent_generics()
+ .and_then(|g| g.find_param(param))
+ // Remember that parent parameters come after parameters for self.
+ .map(|(idx, data)| (self.len_self() + idx, data))
}
}
- fn parent_generics(&self) -> Option<&Generics> {
- self.parent_generics.as_ref().map(|it| &**it)
+ pub(crate) fn parent_generics(&self) -> Option<&Generics> {
+ self.parent_generics.as_deref()
}
/// Returns a Substitution that replaces each parameter by a bound variable.
@@ -295,18 +284,10 @@ impl Generics {
Substitution::from_iter(
Interner,
self.iter_id().enumerate().map(|(idx, id)| match id {
- Either::Left(_) => GenericArgData::Ty(
- TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
- )
- .intern(Interner),
- Either::Right(id) => GenericArgData::Const(
- ConstData {
- value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
- ty: db.const_param_ty(id),
- }
- .intern(Interner),
- )
- .intern(Interner),
+ Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
+ Either::Right(id) => BoundVar::new(debruijn, idx)
+ .to_const(Interner, db.const_param_ty(id))
+ .cast(Interner),
}),
)
}
@@ -316,18 +297,12 @@ impl Generics {
Substitution::from_iter(
Interner,
self.iter_id().map(|id| match id {
- Either::Left(id) => GenericArgData::Ty(
- TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
- )
- .intern(Interner),
- Either::Right(id) => GenericArgData::Const(
- ConstData {
- value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
- ty: db.const_param_ty(id),
- }
- .intern(Interner),
- )
- .intern(Interner),
+ Either::Left(id) => {
+ crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
+ }
+ Either::Right(id) => crate::to_placeholder_idx(db, id.into())
+ .to_const(Interner, db.const_param_ty(id))
+ .cast(Interner),
}),
)
}
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index 8e6a2441b..e1418de3c 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -13,9 +13,9 @@ doctest = false
rustc-hash = "1.1.0"
either = "1.7.0"
arrayvec = "0.7.2"
-itertools = "0.10.3"
-smallvec = "1.9.0"
-once_cell = "1.12.0"
+itertools = "0.10.5"
+smallvec = "1.10.0"
+once_cell = "1.15.0"
stdx = { path = "../stdx", version = "0.0.0" }
syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 5edc16d8b..c5dc60f1e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -1,7 +1,7 @@
//! Re-export diagnostics such that clients of `hir` don't have to depend on
//! low-level crates.
//!
-//! This probably isn't the best way to do this -- ideally, diagnistics should
+//! This probably isn't the best way to do this -- ideally, diagnostics should
//! be expressed in terms of hir types themselves.
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 0e29c52ad..27b2f445d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -492,6 +492,9 @@ impl HirDisplay for TypeAlias {
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
let data = f.db.type_alias_data(self.id);
write!(f, "type {}", data.name)?;
+ let def_id = GenericDefId::TypeAliasId(self.id);
+ write_generic_params(def_id, f)?;
+ write_where_clause(def_id, f)?;
if !data.bounds.is_empty() {
f.write_str(": ")?;
f.write_joined(&data.bounds, " + ")?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
index 9c7558d19..f825a72c0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
@@ -140,6 +140,7 @@ impl From<DefWithBody> for DefWithBodyId {
DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
+ DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()),
}
}
}
@@ -150,6 +151,7 @@ impl From<DefWithBodyId> for DefWithBody {
DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()),
DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()),
DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()),
+ DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()),
}
}
}
@@ -172,9 +174,7 @@ impl From<GenericDef> for GenericDefId {
GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
- GenericDef::Variant(it) => {
- GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
- }
+ GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()),
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
}
}
@@ -188,9 +188,7 @@ impl From<GenericDefId> for GenericDef {
GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
- GenericDefId::EnumVariantId(it) => {
- GenericDef::Variant(Variant { parent: it.parent.into(), id: it.local_id })
- }
+ GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()),
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
}
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index e4bb63a86..f5324208c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -39,7 +39,7 @@ use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
use either::Either;
use hir_def::{
- adt::{ReprKind, VariantData},
+ adt::{ReprData, VariantData},
body::{BodyDiagnostic, SyntheticSyntax},
expr::{BindingAnnotation, LabelId, Pat, PatId},
generics::{TypeOrConstParamData, TypeParamProvenance},
@@ -50,7 +50,7 @@ use hir_def::{
resolver::{HasResolver, Resolver},
src::HasSource as _,
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
- FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+ EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
};
@@ -61,12 +61,10 @@ use hir_ty::{
diagnostics::BodyValidationDiagnostic,
method_resolution::{self, TyFingerprint},
primitive::UintTy,
- subst_prefix,
traits::FnTrait,
- AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
- ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
- QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
- TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
+ AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
+ GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
+ TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
};
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
@@ -74,7 +72,7 @@ use once_cell::unsync::Lazy;
use rustc_hash::FxHashSet;
use stdx::{impl_from, never};
use syntax::{
- ast::{self, HasAttrs as _, HasDocComments, HasName},
+ ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
};
@@ -349,7 +347,10 @@ impl ModuleDef {
ModuleDef::Module(it) => it.id.into(),
ModuleDef::Const(it) => it.id.into(),
ModuleDef::Static(it) => it.id.into(),
- _ => return Vec::new(),
+ ModuleDef::Variant(it) => {
+ EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
+ }
+ ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
};
let module = match self.module(db) {
@@ -378,10 +379,10 @@ impl ModuleDef {
ModuleDef::Function(it) => Some(it.into()),
ModuleDef::Const(it) => Some(it.into()),
ModuleDef::Static(it) => Some(it.into()),
+ ModuleDef::Variant(it) => Some(it.into()),
ModuleDef::Module(_)
| ModuleDef::Adt(_)
- | ModuleDef::Variant(_)
| ModuleDef::Trait(_)
| ModuleDef::TypeAlias(_)
| ModuleDef::Macro(_)
@@ -538,6 +539,30 @@ impl Module {
}
acc.extend(decl.diagnostics(db))
}
+ ModuleDef::Adt(adt) => {
+ match adt {
+ Adt::Struct(s) => {
+ for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+ }
+ Adt::Union(u) => {
+ for diag in db.union_data_with_diagnostics(u.id).1.iter() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+ }
+ Adt::Enum(e) => {
+ for v in e.variants(db) {
+ acc.extend(ModuleDef::Variant(v).diagnostics(db));
+ }
+
+ for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
+ emit_def_diagnostic(db, acc, diag);
+ }
+ }
+ }
+ acc.extend(decl.diagnostics(db))
+ }
_ => acc.extend(decl.diagnostics(db)),
}
}
@@ -582,8 +607,13 @@ impl Module {
/// Finds a path that can be used to refer to the given item from within
/// this module, if possible.
- pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
- hir_def::find_path::find_path(db, item.into().into(), self.into())
+ pub fn find_use_path(
+ self,
+ db: &dyn DefDatabase,
+ item: impl Into<ItemInNs>,
+ prefer_no_std: bool,
+ ) -> Option<ModPath> {
+ hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
}
/// Finds a path that can be used to refer to the given item from within
@@ -593,8 +623,15 @@ impl Module {
db: &dyn DefDatabase,
item: impl Into<ItemInNs>,
prefix_kind: PrefixKind,
+ prefer_no_std: bool,
) -> Option<ModPath> {
- hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
+ hir_def::find_path::find_path_prefixed(
+ db,
+ item.into().into(),
+ self.into(),
+ prefix_kind,
+ prefer_no_std,
+ )
}
}
@@ -863,7 +900,7 @@ impl Struct {
Type::from_def(db, self.id)
}
- pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
+ pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprData> {
db.struct_data(self.id).repr.clone()
}
@@ -941,6 +978,21 @@ impl Enum {
pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::from_def(db, self.id)
}
+
+ /// The type of the enum variant bodies.
+ pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
+ Type::new_for_crate(
+ self.id.lookup(db.upcast()).container.krate(),
+ TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
+ Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
+ Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
+ }),
+ )
+ }
+
+ pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
+ self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
+ }
}
impl HasVisibility for Enum {
@@ -949,6 +1001,12 @@ impl HasVisibility for Enum {
}
}
+impl From<&Variant> for DefWithBodyId {
+ fn from(&v: &Variant) -> Self {
+ DefWithBodyId::VariantId(v.into())
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Variant {
pub(crate) parent: Enum,
@@ -983,6 +1041,14 @@ impl Variant {
pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
}
+
+ pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
+ self.source(db)?.value.expr()
+ }
+
+ pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
+ db.const_eval_variant(self.into())
+ }
}
/// Variants inherit visibility from the parent enum.
@@ -1023,7 +1089,7 @@ impl Adt {
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
let id = AdtId::from(self);
let mut it = args.iter().map(|t| t.ty.clone());
- let ty = TyBuilder::def_ty(db, id.into())
+ let ty = TyBuilder::def_ty(db, id.into(), None)
.fill(|x| {
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
match x {
@@ -1118,8 +1184,9 @@ pub enum DefWithBody {
Function(Function),
Static(Static),
Const(Const),
+ Variant(Variant),
}
-impl_from!(Function, Const, Static for DefWithBody);
+impl_from!(Function, Const, Static, Variant for DefWithBody);
impl DefWithBody {
pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -1127,6 +1194,7 @@ impl DefWithBody {
DefWithBody::Const(c) => c.module(db),
DefWithBody::Function(f) => f.module(db),
DefWithBody::Static(s) => s.module(db),
+ DefWithBody::Variant(v) => v.module(db),
}
}
@@ -1135,6 +1203,7 @@ impl DefWithBody {
DefWithBody::Function(f) => Some(f.name(db)),
DefWithBody::Static(s) => Some(s.name(db)),
DefWithBody::Const(c) => c.name(db),
+ DefWithBody::Variant(v) => Some(v.name(db)),
}
}
@@ -1144,6 +1213,7 @@ impl DefWithBody {
DefWithBody::Function(it) => it.ret_type(db),
DefWithBody::Static(it) => it.ty(db),
DefWithBody::Const(it) => it.ty(db),
+ DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
}
}
@@ -1152,6 +1222,7 @@ impl DefWithBody {
DefWithBody::Function(it) => it.id.into(),
DefWithBody::Static(it) => it.id.into(),
DefWithBody::Const(it) => it.id.into(),
+ DefWithBody::Variant(it) => it.into(),
}
}
@@ -1368,6 +1439,7 @@ impl DefWithBody {
DefWithBody::Function(it) => it.into(),
DefWithBody::Static(it) => it.into(),
DefWithBody::Const(it) => it.into(),
+ DefWithBody::Variant(it) => it.into(),
};
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
acc.push(diag.into())
@@ -2474,7 +2546,7 @@ impl TypeParam {
let resolver = self.id.parent().resolver(db.upcast());
let ty = params.get(local_idx)?.clone();
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
- let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
+ let ty = ty.substitute(Interner, &subst);
match ty.data(Interner) {
GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
_ => None,
@@ -2728,7 +2800,22 @@ impl Type {
}
fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
- let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
+ let ty_def = def.into();
+ let parent_subst = match ty_def {
+ TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => {
+ let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
+ Some(subst)
+ }
+ ItemContainerId::ImplId(id) => {
+ let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
+ Some(subst)
+ }
+ _ => None,
+ },
+ _ => None,
+ };
+ let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
Type::new(db, def, ty)
}
@@ -2868,7 +2955,11 @@ impl Type {
alias: TypeAlias,
) -> Option<Type> {
let mut args = args.iter();
- let projection = TyBuilder::assoc_type_projection(db, alias.id)
+ let trait_id = match alias.id.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => id,
+ _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
+ };
+ let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
.push(self.ty.clone())
.fill(|x| {
// FIXME: this code is not covered in tests.
@@ -2880,27 +2971,14 @@ impl Type {
}
})
.build();
- let goal = hir_ty::make_canonical(
- InEnvironment::new(
- &self.env.env,
- AliasEq {
- alias: AliasTy::Projection(projection),
- ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
- .intern(Interner),
- }
- .cast(Interner),
- ),
- [TyVariableKind::General].into_iter(),
- );
+ // FIXME: We don't handle GATs yet.
+ let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
- match db.trait_solve(self.env.krate, goal)? {
- Solution::Unique(s) => s
- .value
- .subst
- .as_slice(Interner)
- .first()
- .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
- Solution::Ambig(_) => None,
+ let ty = db.normalize_projection(projection, self.env.clone());
+ if ty.is_unknown() {
+ None
+ } else {
+ Some(self.derived(ty))
}
}
@@ -2944,7 +3022,7 @@ impl Type {
let adt = adt_id.into();
match adt {
- Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
+ Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
_ => false,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 416b6f580..119ec3210 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -257,6 +257,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
self.imp.original_ast_node(node)
}
+ /// Attempts to map the node out of macro expanded files.
+ /// This only work for attribute expansions, as other ones do not have nodes as input.
+ pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
+ self.imp.original_syntax_node(node)
+ }
pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
self.imp.diagnostics_display_range(diagnostics)
@@ -956,6 +961,16 @@ impl<'db> SemanticsImpl<'db> {
)
}
+ fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
+ let InFile { file_id, .. } = self.find_file(node);
+ InFile::new(file_id, node).original_syntax_node(self.db.upcast()).map(
+ |InFile { file_id, value }| {
+ self.cache(find_root(&value), file_id);
+ value
+ },
+ )
+ }
+
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
let root = self.parse_or_expand(src.file_id).unwrap();
let node = src.map(|it| it.to_node(&root));
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index ba9a1cfb6..fa45e3c12 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -115,7 +115,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
}
impl SourceToDefCtx<'_, '_> {
- pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
+ pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
let _p = profile::span("SourceBinder::to_module_def");
let mut mods = SmallVec::new();
for &crate_id in self.db.relevant_crates(file).iter() {
@@ -130,7 +130,7 @@ impl SourceToDefCtx<'_, '_> {
mods
}
- pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
+ pub(super) fn module_to_def(&self, src: InFile<ast::Module>) -> Option<ModuleId> {
let _p = profile::span("module_to_def");
let parent_declaration = src
.syntax()
@@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> {
Some(def_map.module_id(child_id))
}
- pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
+ pub(super) fn source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
let _p = profile::span("source_file_to_def");
let file_id = src.file_id.original_file(self.db.upcast());
self.file_to_def(file_id).get(0).copied()
@@ -384,7 +384,7 @@ impl SourceToDefCtx<'_, '_> {
} else {
let it = ast::Variant::cast(container.value)?;
let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
- VariantId::from(def).into()
+ DefWithBodyId::from(def).into()
};
Some(cont)
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 342912b67..07bae2b38 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -22,7 +22,7 @@ use hir_def::{
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
type_ref::Mutability,
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
- Lookup, ModuleDefId, VariantId,
+ Lookup, ModuleDefId, TraitId, VariantId,
};
use hir_expand::{
builtin_fn_macro::BuiltinFnLikeExpander,
@@ -302,10 +302,15 @@ impl SourceAnalyzer {
}
}
+ let future_trait = db
+ .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
+ .as_trait()?;
let poll_fn = db
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
.as_function()?;
- let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
+ // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
+ // doesn't have any generic parameters, so we skip building another subst for `poll()`.
+ let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
}
@@ -321,8 +326,10 @@ impl SourceAnalyzer {
};
let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
- let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
- let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+ let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ // HACK: subst for all methods coincides with that for their trait because the methods
+ // don't have any generic parameters, so we skip building another subst for the methods.
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
}
@@ -337,8 +344,10 @@ impl SourceAnalyzer {
let lang_item_name = name![index];
- let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
- let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+ let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ // HACK: subst for all methods coincides with that for their trait because the methods
+ // don't have any generic parameters, so we skip building another subst for the methods.
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
.push(base_ty.clone())
.push(index_ty.clone())
.build();
@@ -354,10 +363,14 @@ impl SourceAnalyzer {
let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
- let op_fn = lang_names_for_bin_op(op)
+ let (op_trait, op_fn) = lang_names_for_bin_op(op)
.and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
- let substs =
- hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+ // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
+ // doesn't have any generic parameters, so we skip building another subst for `index()`.
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
+ .push(lhs.clone())
+ .push(rhs.clone())
+ .build();
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
}
@@ -371,7 +384,13 @@ impl SourceAnalyzer {
let op_fn =
db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
- let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+ let op_trait = match op_fn.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => id,
+ _ => return None,
+ };
+ // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
+ // doesn't have any generic parameters, so we skip building another subst for `branch()`.
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
}
@@ -799,9 +818,10 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
lang_trait: &Name,
method_name: &Name,
- ) -> Option<FunctionId> {
- db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
- .method_by_name(method_name)
+ ) -> Option<(TraitId, FunctionId)> {
+ let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
+ let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
+ Some((trait_id, fn_id))
}
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index 616a406c7..fd78decda 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -244,6 +244,10 @@ impl<'a> SymbolCollector<'a> {
DefWithBodyId::ConstId(id) => Some(
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
),
+ DefWithBodyId::VariantId(id) => Some({
+ let db = self.db.upcast();
+ id.parent.lookup(db).source(db).value.name()?.text().into()
+ }),
}
}