Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs710
1 files changed, 559 insertions, 151 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 35424feec8..5926d86542 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -6,7 +6,7 @@
//! applied. So, the relation between syntax and HIR is many-to-one.
//!
//! HIR is the public API of the all of the compiler logic above syntax trees.
-//! It is written in "OO" style. Each type is self contained (as in, it knows it's
+//! It is written in "OO" style. Each type is self contained (as in, it knows its
//! parents and full context). It should be "clean code".
//!
//! `hir_*` crates are the implementation of the compiler logic.
@@ -33,24 +33,25 @@ pub mod symbols;
mod display;
-use std::{iter, ops::ControlFlow, sync::Arc};
+use std::{iter, ops::ControlFlow};
use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
use either::Either;
use hir_def::{
- adt::VariantData,
body::{BodyDiagnostic, SyntheticSyntax},
- expr::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
+ data::adt::VariantData,
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
+ hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
item_tree::ItemTreeNode,
- lang_item::{LangItem, LangItemTarget},
- layout::{Layout, LayoutError, ReprOptions},
+ lang_item::LangItemTarget,
+ layout::{self, ReprOptions, TargetDataLayout},
+ macro_id_to_def_id,
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
per_ns::PerNs,
resolver::{HasResolver, Resolver},
src::HasSource as _,
- AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+ AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
@@ -61,14 +62,15 @@ use hir_ty::{
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic,
display::HexifiedConst,
- layout::layout_of_ty,
+ layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding},
method_resolution::{self, TyFingerprint},
mir::{self, interpret_mir},
primitive::UintTy,
traits::FnTrait,
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
- TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
+ TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
+ WhereClause,
};
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
@@ -79,6 +81,7 @@ use syntax::{
ast::{self, HasAttrs as _, HasDocComments, HasName},
AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, T,
};
+use triomphe::Arc;
use crate::db::{DefDatabase, HirDatabase};
@@ -86,11 +89,13 @@ pub use crate::{
attrs::{HasAttrs, Namespace},
diagnostics::{
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl,
- IncorrectCase, InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount,
- MissingFields, MissingMatchArms, MissingUnsafe, NeedMut, NoSuchField, PrivateAssocItem,
- PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
- UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall,
- UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut,
+ IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MacroExpansionParseError,
+ MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe,
+ MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField,
+ ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel,
+ UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField,
+ UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule,
+ UnresolvedProcMacro, UnusedMut,
},
has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
@@ -108,20 +113,18 @@ pub use crate::{
pub use {
cfg::{CfgAtom, CfgExpr, CfgOptions},
hir_def::{
- adt::StructKind,
- attr::{Attrs, AttrsWithOwner, Documentation},
- builtin_attr::AttributeTemplate,
+ attr::{builtin::AttributeTemplate, Attrs, AttrsWithOwner, Documentation},
+ data::adt::StructKind,
find_path::PrefixKind,
import_map,
- nameres::ModuleSource,
+ lang_item::LangItem,
+ nameres::{DefMap, ModuleSource},
path::{ModPath, PathKind},
type_ref::{Mutability, TypeRef},
visibility::Visibility,
- // FIXME: This is here since it is input of a method in `HirWrite`
- // and things outside of hir need to implement that trait. We probably
- // should move whole `hir_ty::display` to this crate so we will become
- // able to use `ModuleDef` or `Definition` instead of `ModuleDefId`.
- ModuleDefId,
+ // FIXME: This is here since some queries take it as input that are used
+ // outside of hir.
+ {AdtId, ModuleDefId},
},
hir_expand::{
attrs::Attr,
@@ -129,7 +132,8 @@ pub use {
ExpandResult, HirFileId, InFile, MacroFile, Origin,
},
hir_ty::{
- display::{HirDisplay, HirDisplayError, HirWrite},
+ display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
+ layout::LayoutError,
mir::MirEvalError,
PointerCast, Safety,
},
@@ -198,7 +202,7 @@ impl Crate {
pub fn root_module(self, db: &dyn HirDatabase) -> Module {
let def_map = db.crate_def_map(self.id);
- Module { id: def_map.module_id(def_map.root()) }
+ Module { id: def_map.module_id(DefMap::ROOT) }
}
pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
@@ -253,7 +257,8 @@ impl Crate {
}
pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
- db.crate_graph()[self.id].potential_cfg_options.clone()
+ let data = &db.crate_graph()[self.id];
+ data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone())
}
}
@@ -326,7 +331,7 @@ impl ModuleDef {
segments.extend(m.name(db))
}
segments.reverse();
- Some(segments.into_iter().join("::"))
+ Some(segments.iter().map(|it| it.display(db.upcast())).join("::"))
}
pub fn canonical_module_path(
@@ -470,12 +475,11 @@ impl Module {
/// in the module tree of any target in `Cargo.toml`.
pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
let def_map = db.crate_def_map(self.id.krate());
- Module { id: def_map.module_id(def_map.root()) }
+ Module { id: def_map.module_id(DefMap::ROOT) }
}
- pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
- let def_map = db.crate_def_map(self.id.krate());
- def_map.root() == self.id.local_id
+ pub fn is_crate_root(self) -> bool {
+ DefMap::ROOT == self.id.local_id
}
/// Iterates over all child modules.
@@ -552,7 +556,11 @@ impl Module {
/// Fills `acc` with the module's diagnostics.
pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
let _p = profile::span("Module::diagnostics").detail(|| {
- format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
+ format!(
+ "{:?}",
+ self.name(db)
+ .map_or("<unknown>".into(), |name| name.display(db.upcast()).to_string())
+ )
});
let def_map = self.id.def_map(db.upcast());
for diag in def_map.diagnostics() {
@@ -562,6 +570,7 @@ impl Module {
}
emit_def_diagnostic(db, acc, diag);
}
+
for decl in self.declarations(db) {
match decl {
ModuleDef::Module(m) => {
@@ -600,9 +609,11 @@ impl Module {
}
acc.extend(decl.diagnostics(db))
}
+ ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m),
_ => acc.extend(decl.diagnostics(db)),
}
}
+ self.legacy_macros(db).into_iter().for_each(|m| emit_macro_def_diagnostics(db, acc, m));
let inherent_impls = db.inherent_impls_in_crate(self.id.krate());
@@ -684,8 +695,31 @@ impl Module {
}
}
+fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
+ let id = macro_id_to_def_id(db.upcast(), m.id);
+ if let Err(e) = db.macro_def(id) {
+ let Some(ast) = id.ast_id().left() else {
+ never!("MacroDefError for proc-macro: {:?}", e);
+ return;
+ };
+ emit_def_diagnostic_(
+ db,
+ acc,
+ &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() },
+ );
+ }
+}
+
fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
- match &diag.kind {
+ emit_def_diagnostic_(db, acc, &diag.kind)
+}
+
+fn emit_def_diagnostic_(
+ db: &dyn HirDatabase,
+ acc: &mut Vec<AnyDiagnostic>,
+ diag: &DefDiagnosticKind,
+) {
+ match diag {
DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
let decl = declaration.to_node(db.upcast());
acc.push(
@@ -725,7 +759,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
.into(),
);
}
-
DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
acc.push(
@@ -733,7 +766,6 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
.into(),
);
}
-
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
acc.push(
@@ -746,12 +778,16 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
.into(),
);
}
-
DefDiagnosticKind::MacroError { ast, message } => {
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
acc.push(MacroError { node, precise_location, message: message.clone() }.into());
}
-
+ DefDiagnosticKind::MacroExpansionParseError { ast, errors } => {
+ let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
+ acc.push(
+ MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(),
+ );
+ }
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
let node = ast.to_node(db.upcast());
// Must have a name, otherwise we wouldn't emit it.
@@ -793,6 +829,17 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
None => stdx::never!("derive diagnostic on item without derive attribute"),
}
}
+ DefDiagnosticKind::MacroDefError { ast, message } => {
+ let node = ast.to_node(db.upcast());
+ acc.push(
+ MacroDefError {
+ node: InFile::new(ast.file_id, AstPtr::new(&node)),
+ name: node.name().map(|it| it.syntax().text_range()),
+ message: message.clone(),
+ }
+ .into(),
+ );
+ }
}
}
@@ -800,7 +847,7 @@ fn precise_macro_call_location(
ast: &MacroCallKind,
db: &dyn HirDatabase,
) -> (InFile<SyntaxNodePtr>, Option<TextRange>, Option<String>, MacroKind) {
- // FIXME: maaybe we actually want slightly different ranges for the different macro diagnostics
+ // FIXME: maybe we actually want slightly different ranges for the different macro diagnostics
// - e.g. the full attribute for macro errors, but only the name for name resolution
match ast {
MacroCallKind::FnLike { ast_id, .. } => {
@@ -915,7 +962,8 @@ impl Field {
}
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
- layout_of_ty(db, &self.ty(db).ty, self.parent.module(db).krate().into())
+ db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
+ .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
}
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@@ -959,6 +1007,10 @@ impl Struct {
Type::from_def(db, self.id)
}
+ pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+ Type::from_value_def(db, self.id)
+ }
+
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
db.struct_data(self.id).repr
}
@@ -996,6 +1048,10 @@ impl Union {
Type::from_def(db, self.id)
}
+ pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+ Type::from_value_def(db, self.id)
+ }
+
pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
db.union_data(self.id)
.variant_data
@@ -1034,6 +1090,10 @@ impl Enum {
db.enum_data(self.id).variants.iter().map(|(id, _)| Variant { parent: self, id }).collect()
}
+ pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
+ db.enum_data(self.id).repr
+ }
+
pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::from_def(db, self.id)
}
@@ -1043,7 +1103,7 @@ impl Enum {
Type::new_for_crate(
self.id.lookup(db.upcast()).container.krate(),
TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
- hir_def::layout::IntegerType::Pointer(sign) => match sign {
+ layout::IntegerType::Pointer(sign) => match sign {
true => hir_def::builtin_type::BuiltinType::Int(
hir_def::builtin_type::BuiltinInt::Isize,
),
@@ -1051,29 +1111,34 @@ impl Enum {
hir_def::builtin_type::BuiltinUint::Usize,
),
},
- hir_def::layout::IntegerType::Fixed(i, sign) => match sign {
+ layout::IntegerType::Fixed(i, sign) => match sign {
true => hir_def::builtin_type::BuiltinType::Int(match i {
- hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8,
- hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16,
- hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32,
- hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64,
- hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128,
+ layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8,
+ layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16,
+ layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32,
+ layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64,
+ layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128,
}),
false => hir_def::builtin_type::BuiltinType::Uint(match i {
- hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8,
- hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16,
- hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32,
- hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64,
- hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128,
+ layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8,
+ layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16,
+ layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32,
+ layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64,
+ layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128,
}),
},
}),
)
}
+ /// Returns true if at least one variant of this enum is a non-unit variant.
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
}
+
+ pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+ Adt::from(self).layout(db)
+ }
}
impl HasVisibility for Enum {
@@ -1103,6 +1168,10 @@ impl Variant {
self.parent
}
+ pub fn constructor_ty(self, db: &dyn HirDatabase) -> Type {
+ Type::from_value_def(db, EnumVariantId { parent: self.parent.id, local_id: self.id })
+ }
+
pub fn name(self, db: &dyn HirDatabase) -> Name {
db.enum_data(self.parent.id).variants[self.id].name.clone()
}
@@ -1130,6 +1199,18 @@ impl Variant {
pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> {
db.const_eval_discriminant(self.into())
}
+
+ pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+ let parent_enum = self.parent_enum(db);
+ let parent_layout = parent_enum.layout(db)?;
+ Ok(match &parent_layout.0.variants {
+ layout::Variants::Multiple { variants, .. } => Layout(
+ Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()),
+ db.target_data_layout(parent_enum.krate(db).into()).unwrap(),
+ ),
+ _ => parent_layout,
+ })
+ }
}
/// Variants inherit visibility from the parent enum.
@@ -1161,7 +1242,9 @@ impl Adt {
if db.generic_params(self.into()).iter().count() != 0 {
return Err(LayoutError::HasPlaceholder);
}
- db.layout_of_adt(self.into(), Substitution::empty(Interner))
+ let krate = self.krate(db).id;
+ db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
+ .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
}
/// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -1392,6 +1475,12 @@ impl DefWithBody {
}
.into(),
),
+ BodyDiagnostic::UnreachableLabel { node, name } => {
+ acc.push(UnreachableLabel { node: node.clone(), name: name.clone() }.into())
+ }
+ BodyDiagnostic::UndeclaredLabel { node, name } => {
+ acc.push(UndeclaredLabel { node: node.clone(), name: name.clone() }.into())
+ }
}
}
@@ -1404,14 +1493,6 @@ impl DefWithBody {
let field = source_map.field_syntax(expr);
acc.push(NoSuchField { field }.into())
}
- &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
- expr,
- is_break,
- bad_value_break,
- } => {
- let expr = expr_syntax(expr);
- acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
- }
&hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
acc.push(
MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found }
@@ -1483,14 +1564,29 @@ impl DefWithBody {
.into(),
)
}
+ &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
+ expr,
+ is_break,
+ bad_value_break,
+ } => {
+ let expr = expr_syntax(expr);
+ acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
+ }
+ hir_ty::InferenceDiagnostic::TypedHole { expr, expected } => {
+ let expr = expr_syntax(*expr);
+ acc.push(
+ TypedHole {
+ expr,
+ expected: Type::new(db, DefWithBodyId::from(self), expected.clone()),
+ }
+ .into(),
+ )
+ }
}
}
for (pat_or_expr, mismatch) in infer.type_mismatches() {
let expr_or_pat = match pat_or_expr {
ExprOrPatId::ExprId(expr) => source_map.expr_syntax(expr).map(Either::Left),
- // FIXME: Re-enable these once we have less false positives
- ExprOrPatId::PatId(_pat) => continue,
- #[allow(unreachable_patterns)]
ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right),
};
let expr_or_pat = match expr_or_pat {
@@ -1515,7 +1611,7 @@ impl DefWithBody {
match source_map.expr_syntax(expr) {
Ok(expr) => acc.push(MissingUnsafe { expr }.into()),
Err(SyntheticSyntax) => {
- // FIXME: Here and eslwhere in this file, the `expr` was
+ // FIXME: Here and elsewhere in this file, the `expr` was
// desugared, report or assert that this doesn't happen.
}
}
@@ -1523,35 +1619,71 @@ impl DefWithBody {
let hir_body = db.body(self.into());
- if let Ok(borrowck_result) = db.borrowck(self.into()) {
- let mir_body = &borrowck_result.mir_body;
- let mol = &borrowck_result.mutability_of_locals;
- for (binding_id, _) in hir_body.bindings.iter() {
- let need_mut = &mol[mir_body.binding_locals[binding_id]];
- let local = Local { parent: self.into(), binding_id };
- match (need_mut, local.is_mut(db)) {
- (mir::MutabilityReason::Mut { .. }, true)
- | (mir::MutabilityReason::Not, false) => (),
- (mir::MutabilityReason::Mut { spans }, false) => {
- for span in spans {
- let span: InFile<SyntaxNodePtr> = match span {
- mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {
- Ok(s) => s.map(|x| x.into()),
- Err(_) => continue,
- },
- mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
- Ok(s) => s.map(|x| match x {
- Either::Left(e) => e.into(),
- Either::Right(e) => e.into(),
- }),
- Err(_) => continue,
- },
- mir::MirSpan::Unknown => continue,
- };
- acc.push(NeedMut { local, span }.into());
+ if let Ok(borrowck_results) = db.borrowck(self.into()) {
+ for borrowck_result in borrowck_results.iter() {
+ let mir_body = &borrowck_result.mir_body;
+ for moof in &borrowck_result.moved_out_of_ref {
+ let span: InFile<SyntaxNodePtr> = match moof.span {
+ mir::MirSpan::ExprId(e) => match source_map.expr_syntax(e) {
+ Ok(s) => s.map(|x| x.into()),
+ Err(_) => continue,
+ },
+ mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) {
+ Ok(s) => s.map(|x| match x {
+ Either::Left(e) => e.into(),
+ Either::Right(e) => e.into(),
+ }),
+ Err(_) => continue,
+ },
+ mir::MirSpan::Unknown => continue,
+ };
+ acc.push(
+ MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span }
+ .into(),
+ )
+ }
+ let mol = &borrowck_result.mutability_of_locals;
+ for (binding_id, binding_data) in hir_body.bindings.iter() {
+ if binding_data.problems.is_some() {
+ // We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`.
+ continue;
+ }
+ let Some(&local) = mir_body.binding_locals.get(binding_id) else {
+ continue;
+ };
+ let need_mut = &mol[local];
+ let local = Local { parent: self.into(), binding_id };
+ match (need_mut, local.is_mut(db)) {
+ (mir::MutabilityReason::Mut { .. }, true)
+ | (mir::MutabilityReason::Not, false) => (),
+ (mir::MutabilityReason::Mut { spans }, false) => {
+ for span in spans {
+ let span: InFile<SyntaxNodePtr> = match span {
+ mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) {
+ Ok(s) => s.map(|x| x.into()),
+ Err(_) => continue,
+ },
+ mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
+ Ok(s) => s.map(|x| match x {
+ Either::Left(e) => e.into(),
+ Either::Right(e) => e.into(),
+ }),
+ Err(_) => continue,
+ },
+ mir::MirSpan::Unknown => continue,
+ };
+ acc.push(NeedMut { local, span }.into());
+ }
+ }
+ (mir::MutabilityReason::Not, true) => {
+ if !infer.mutated_bindings_in_closure.contains(&binding_id) {
+ let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_"));
+ if !should_ignore {
+ acc.push(UnusedMut { local }.into())
+ }
+ }
}
}
- (mir::MutabilityReason::Not, true) => acc.push(UnusedMut { local }.into()),
}
}
}
@@ -1686,6 +1818,10 @@ impl Function {
db.function_data(self.id).name.clone()
}
+ pub fn ty(self, db: &dyn HirDatabase) -> Type {
+ Type::from_value_def(db, self.id)
+ }
+
/// Get this function's return type
pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
let resolver = self.id.resolver(db.upcast());
@@ -1797,12 +1933,41 @@ impl Function {
def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
}
- pub fn eval(self, db: &dyn HirDatabase) -> Result<(), MirEvalError> {
- let body = db
- .mir_body(self.id.into())
- .map_err(|e| MirEvalError::MirLowerError(self.id.into(), e))?;
- interpret_mir(db, &body, false)?;
- Ok(())
+ pub fn eval(
+ self,
+ db: &dyn HirDatabase,
+ span_formatter: impl Fn(FileId, TextRange) -> String,
+ ) -> String {
+ let body = match db.monomorphized_mir_body(
+ self.id.into(),
+ Substitution::empty(Interner),
+ db.trait_environment(self.id.into()),
+ ) {
+ Ok(body) => body,
+ Err(e) => {
+ let mut r = String::new();
+ _ = e.pretty_print(&mut r, db, &span_formatter);
+ return r;
+ }
+ };
+ let (result, stdout, stderr) = interpret_mir(db, &body, false);
+ let mut text = match result {
+ Ok(_) => "pass".to_string(),
+ Err(e) => {
+ let mut r = String::new();
+ _ = e.pretty_print(&mut r, db, &span_formatter);
+ r
+ }
+ };
+ if !stdout.is_empty() {
+ text += "\n--------- stdout ---------\n";
+ text += &stdout;
+ }
+ if !stderr.is_empty() {
+ text += "\n--------- stderr ---------\n";
+ text += &stderr;
+ }
+ text
}
}
@@ -1837,7 +2002,7 @@ impl Param {
}
pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
- db.function_data(self.func.id).params[self.idx].0.clone()
+ Some(self.as_local(db)?.name(db))
}
pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
@@ -1878,7 +2043,7 @@ impl SelfParam {
func_data
.params
.first()
- .map(|(_, param)| match &**param {
+ .map(|param| match &**param {
TypeRef::Reference(.., mutability) => match mutability {
hir_def::type_ref::Mutability::Shared => Access::Shared,
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
@@ -1939,24 +2104,12 @@ impl Const {
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
- let data = db.const_data(self.id);
- let resolver = self.id.resolver(db.upcast());
- let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
- let ty = ctx.lower_ty(&data.type_ref);
- Type::new_with_resolver_inner(db, &resolver, ty)
+ Type::from_value_def(db, self.id)
}
pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
- let c = db.const_eval(self.id)?;
+ let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
let r = format!("{}", HexifiedConst(c).display(db));
- // We want to see things like `<utf8-error>` and `<layout-error>` as they are probably bug in our
- // implementation, but there is no need to show things like `<enum-not-supported>` or `<ref-not-supported>` to
- // the user.
- if r.contains("not-supported>") {
- return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported(
- "rendering complex constants".to_string(),
- )));
- }
return Ok(r);
}
}
@@ -1990,11 +2143,7 @@ impl Static {
}
pub fn ty(self, db: &dyn HirDatabase) -> Type {
- let data = db.static_data(self.id);
- let resolver = self.id.resolver(db.upcast());
- let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
- let ty = ctx.lower_ty(&data.type_ref);
- Type::new_with_resolver_inner(db, &resolver, ty)
+ Type::from_value_def(db, self.id)
}
}
@@ -2545,8 +2694,12 @@ impl LocalSource {
self.source.file_id.original_file(db.upcast())
}
- pub fn name(&self) -> Option<ast::Name> {
- self.source.value.name()
+ pub fn file(&self) -> HirFileId {
+ self.source.file_id
+ }
+
+ pub fn name(&self) -> Option<InFile<ast::Name>> {
+ self.source.as_ref().map(|it| it.name()).transpose()
}
pub fn syntax(&self) -> &SyntaxNode {
@@ -2689,9 +2842,7 @@ impl BuiltinAttr {
}
fn builtin(name: &str) -> Option<Self> {
- hir_def::builtin_attr::INERT_ATTRIBUTES
- .iter()
- .position(|tool| tool.name == name)
+ hir_def::attr::builtin::find_builtin_attr_idx(name)
.map(|idx| BuiltinAttr { krate: None, idx: idx as u32 })
}
@@ -2699,14 +2850,14 @@ impl BuiltinAttr {
// FIXME: Return a `Name` here
match self.krate {
Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
- None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].name),
+ None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name),
}
}
pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
match self.krate {
Some(_) => None,
- None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].template),
+ None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template),
}
}
}
@@ -2729,7 +2880,7 @@ impl ToolModule {
}
fn builtin(name: &str) -> Option<Self> {
- hir_def::builtin_attr::TOOL_MODULES
+ hir_def::attr::builtin::TOOL_MODULES
.iter()
.position(|&tool| tool == name)
.map(|idx| ToolModule { krate: None, idx: idx as u32 })
@@ -2739,7 +2890,7 @@ impl ToolModule {
// FIXME: Return a `Name` here
match self.krate {
Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx as usize].clone(),
- None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx as usize]),
+ None => SmolStr::new(hir_def::attr::builtin::TOOL_MODULES[self.idx as usize]),
}
}
}
@@ -3117,6 +3268,103 @@ impl TraitRef {
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Closure {
+ id: ClosureId,
+ subst: Substitution,
+}
+
+impl From<Closure> for ClosureId {
+ fn from(value: Closure) -> Self {
+ value.id
+ }
+}
+
+impl Closure {
+ fn as_ty(self) -> Ty {
+ TyKind::Closure(self.id, self.subst).intern(Interner)
+ }
+
+ pub fn display_with_id(&self, db: &dyn HirDatabase) -> String {
+ self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string()
+ }
+
+ pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String {
+ self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string()
+ }
+
+ pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec<ClosureCapture> {
+ let owner = db.lookup_intern_closure((self.id).into()).0;
+ let infer = &db.infer(owner);
+ let info = infer.closure_info(&self.id);
+ info.0
+ .iter()
+ .cloned()
+ .map(|capture| ClosureCapture { owner, closure: self.id, capture })
+ .collect()
+ }
+
+ pub fn capture_types(&self, db: &dyn HirDatabase) -> Vec<Type> {
+ let owner = db.lookup_intern_closure((self.id).into()).0;
+ let infer = &db.infer(owner);
+ let (captures, _) = infer.closure_info(&self.id);
+ captures
+ .iter()
+ .cloned()
+ .map(|capture| Type {
+ env: db.trait_environment_for_body(owner),
+ ty: capture.ty(&self.subst),
+ })
+ .collect()
+ }
+
+ pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait {
+ let owner = db.lookup_intern_closure((self.id).into()).0;
+ let infer = &db.infer(owner);
+ let info = infer.closure_info(&self.id);
+ info.1
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ClosureCapture {
+ owner: DefWithBodyId,
+ closure: ClosureId,
+ capture: hir_ty::CapturedItem,
+}
+
+impl ClosureCapture {
+ pub fn local(&self) -> Local {
+ Local { parent: self.owner, binding_id: self.capture.local() }
+ }
+
+ pub fn kind(&self) -> CaptureKind {
+ match self.capture.kind() {
+ hir_ty::CaptureKind::ByRef(
+ hir_ty::mir::BorrowKind::Shallow | hir_ty::mir::BorrowKind::Shared,
+ ) => CaptureKind::SharedRef,
+ hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Unique) => {
+ CaptureKind::UniqueSharedRef
+ }
+ hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut { .. }) => {
+ CaptureKind::MutableRef
+ }
+ hir_ty::CaptureKind::ByValue => CaptureKind::Move,
+ }
+ }
+
+ pub fn display_place(&self, db: &dyn HirDatabase) -> String {
+ self.capture.display_place(self.owner, db)
+ }
+}
+
+pub enum CaptureKind {
+ SharedRef,
+ UniqueSharedRef,
+ MutableRef,
+ Move,
+}
+
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Type {
env: Arc<TraitEnvironment>,
@@ -3164,24 +3412,33 @@ impl Type {
Type { env: environment, ty }
}
- fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
- 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,
+ fn from_def(db: &dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Type {
+ let ty = db.ty(def.into());
+ let substs = TyBuilder::unknown_subst(
+ db,
+ match def.into() {
+ TyDefId::AdtId(it) => GenericDefId::AdtId(it),
+ TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
+ TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()),
},
- _ => None,
- };
- let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
- Type::new(db, def, ty)
+ );
+ Type::new(db, def, ty.substitute(Interner, &substs))
+ }
+
+ fn from_value_def(db: &dyn HirDatabase, def: impl Into<ValueTyDefId> + HasResolver) -> Type {
+ let ty = db.value_ty(def.into());
+ let substs = TyBuilder::unknown_subst(
+ db,
+ match def.into() {
+ ValueTyDefId::ConstId(it) => GenericDefId::ConstId(it),
+ ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it),
+ ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)),
+ ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)),
+ ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it),
+ ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()),
+ },
+ );
+ Type::new(db, def, ty.substitute(Interner, &substs))
}
pub fn new_slice(ty: Type) -> Type {
@@ -3331,7 +3588,7 @@ impl Type {
binders: CanonicalVarKinds::empty(Interner),
};
- db.trait_solve(self.env.krate, goal).is_some()
+ db.trait_solve(self.env.krate, self.env.block, goal).is_some()
}
pub fn normalize_trait_assoc_type(
@@ -3378,7 +3635,12 @@ impl Type {
}
pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
+ let mut the_ty = &self.ty;
let callee = match self.ty.kind(Interner) {
+ TyKind::Ref(_, _, ty) if ty.as_closure().is_some() => {
+ the_ty = ty;
+ Callee::Closure(ty.as_closure().unwrap())
+ }
TyKind::Closure(id, _) => Callee::Closure(*id),
TyKind::Function(_) => Callee::FnPtr,
TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
@@ -3393,7 +3655,7 @@ impl Type {
}
};
- let sig = self.ty.callable_sig(db)?;
+ let sig = the_ty.callable_sig(db)?;
Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
}
@@ -3401,6 +3663,13 @@ impl Type {
matches!(self.ty.kind(Interner), TyKind::Closure { .. })
}
+ pub fn as_closure(&self) -> Option<Closure> {
+ match self.ty.kind(Interner) {
+ TyKind::Closure(id, subst) => Some(Closure { id: *id, subst: subst.clone() }),
+ _ => None,
+ }
+ }
+
pub fn is_fn(&self) -> bool {
matches!(self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
}
@@ -3502,9 +3771,9 @@ impl Type {
}
}
- pub fn as_array(&self, _db: &dyn HirDatabase) -> Option<(Type, usize)> {
+ pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> {
if let TyKind::Array(ty, len) = &self.ty.kind(Interner) {
- try_const_usize(len).map(|x| (self.derived(ty.clone()), x as usize))
+ try_const_usize(db, len).map(|x| (self.derived(ty.clone()), x as usize))
} else {
None
}
@@ -3517,8 +3786,7 @@ impl Type {
fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
// There should be no inference vars in types passed here
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
- let environment = self.env.clone();
- autoderef(db, environment, canonical).map(|canonical| canonical.value)
+ autoderef(db, self.env.clone(), canonical).map(|canonical| canonical.value)
}
// This would be nicer if it just returned an iterator, but that runs into
@@ -3636,7 +3904,7 @@ impl Type {
self.as_adt()
.and_then(|a| a.lifetime(db).and_then(|lt| Some((&lt.name).to_smol_str())))
.into_iter()
- // add the type and const paramaters
+ // add the type and const parameters
.chain(self.type_and_const_arguments(db))
}
@@ -3955,6 +4223,11 @@ impl Type {
.map(|id| TypeOrConstParam { id }.split(db).either_into())
.collect()
}
+
+ pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
+ db.layout_of_ty(self.ty.clone(), self.env.krate)
+ .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
+ }
}
// FIXME: Document this
@@ -4064,6 +4337,48 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::Closu
}
}
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Layout(Arc<TyLayout>, Arc<TargetDataLayout>);
+
+impl Layout {
+ pub fn size(&self) -> u64 {
+ self.0.size.bytes()
+ }
+
+ pub fn align(&self) -> u64 {
+ self.0.align.abi.bytes()
+ }
+
+ pub fn niches(&self) -> Option<u128> {
+ Some(self.0.largest_niche?.available(&*self.1))
+ }
+
+ pub fn field_offset(&self, idx: usize) -> Option<u64> {
+ match self.0.fields {
+ layout::FieldsShape::Primitive => None,
+ layout::FieldsShape::Union(_) => Some(0),
+ layout::FieldsShape::Array { stride, count } => {
+ let i = u64::try_from(idx).ok()?;
+ (i < count).then_some((stride * i).bytes())
+ }
+ layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()),
+ }
+ }
+
+ pub fn enum_tag_size(&self) -> Option<usize> {
+ let tag_size =
+ if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants {
+ match tag_encoding {
+ TagEncoding::Direct => tag.size(&*self.1).bytes_usize(),
+ TagEncoding::Niche { .. } => 0,
+ }
+ } else {
+ return None;
+ };
+ Some(tag_size)
+ }
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BindingMode {
Move,
@@ -4215,6 +4530,12 @@ impl HasCrate for Union {
}
}
+impl HasCrate for Enum {
+ fn krate(&self, db: &dyn HirDatabase) -> Crate {
+ self.module(db).krate()
+ }
+}
+
impl HasCrate for Field {
fn krate(&self, db: &dyn HirDatabase) -> Crate {
self.parent_def(db).module(db).krate()
@@ -4286,3 +4607,90 @@ impl HasCrate for Module {
Module::krate(*self)
}
}
+
+pub trait HasContainer {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer;
+}
+
+impl HasContainer for Module {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ // FIXME: handle block expressions as modules (their parent is in a different DefMap)
+ let def_map = self.id.def_map(db.upcast());
+ match def_map[self.id.local_id].parent {
+ Some(parent_id) => ItemContainer::Module(Module { id: def_map.module_id(parent_id) }),
+ None => ItemContainer::Crate(def_map.krate()),
+ }
+ }
+}
+
+impl HasContainer for Function {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ container_id_to_hir(self.id.lookup(db.upcast()).container)
+ }
+}
+
+impl HasContainer for Struct {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+ }
+}
+
+impl HasContainer for Union {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+ }
+}
+
+impl HasContainer for Enum {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+ }
+}
+
+impl HasContainer for TypeAlias {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ container_id_to_hir(self.id.lookup(db.upcast()).container)
+ }
+}
+
+impl HasContainer for Const {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ container_id_to_hir(self.id.lookup(db.upcast()).container)
+ }
+}
+
+impl HasContainer for Static {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ container_id_to_hir(self.id.lookup(db.upcast()).container)
+ }
+}
+
+impl HasContainer for Trait {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+ }
+}
+
+impl HasContainer for TraitAlias {
+ fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
+ ItemContainer::Module(Module { id: self.id.lookup(db.upcast()).container })
+ }
+}
+
+fn container_id_to_hir(c: ItemContainerId) -> ItemContainer {
+ match c {
+ ItemContainerId::ExternBlockId(_id) => ItemContainer::ExternBlock(),
+ ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }),
+ ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }),
+ ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }),
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ItemContainer {
+ Trait(Trait),
+ Impl(Impl),
+ Module(Module),
+ ExternBlock(),
+ Crate(CrateId),
+}