Merge commit '258b15c506' into sync-from-ra

This commit is contained in:
Laurențiu Nicola 2023-09-18 12:32:37 +03:00
parent 7e786ea4cf
commit bcfc997eac
195 changed files with 5773 additions and 2750 deletions

View file

@ -499,24 +499,26 @@ fn offset() {
r#"
//- minicore: coerce_unsized, index, slice
extern "rust-intrinsic" {
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
}
const GOAL: u8 = unsafe {
let ar: &[(u8, u8, u8)] = &[
const GOAL: i32 = unsafe {
let ar: &[(i32, i32, i32)] = &[
(10, 11, 12),
(20, 21, 22),
(30, 31, 32),
(40, 41, 42),
(50, 51, 52),
];
let ar: *const [(u8, u8, u8)] = ar;
let ar = ar as *const (u8, u8, u8);
let element = *offset(ar, 2);
element.1
let ar: *const [(i32, i32, i32)] = ar;
let ar = ar as *const (i32, i32, i32);
let element3 = *offset(ar, 2usize);
let element4 = *arith_offset(ar, 3);
element3.1 * 100 + element4.0
};
"#,
31,
3140,
);
}
@ -584,6 +586,24 @@ fn write_bytes() {
);
}
#[test]
fn write_via_move() {
check_number(
r#"
extern "rust-intrinsic" {
fn write_via_move<T>(ptr: *mut T, value: T);
}
const GOAL: i32 = unsafe {
let mut x = 2;
write_via_move(&mut x, 100);
x
};
"#,
100,
);
}
#[test]
fn copy() {
check_number(

View file

@ -163,25 +163,56 @@ impl<'a> DeclValidator<'a> {
|| allows.contains(allow::NONSTANDARD_STYLE)
})
};
is_allowed(id)
// go upwards one step or give up
|| match id {
AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()),
AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()),
AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
AttrDefId::TraitAliasId(taid) => Some(taid.lookup(self.db.upcast()).container.into()),
AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()),
AttrDefId::ExternCrateId(id) => Some(id.lookup(self.db.upcast()).container.into()),
AttrDefId::UseId(id) => Some(id.lookup(self.db.upcast()).container.into()),
let db = self.db.upcast();
let file_id_is_derive = || {
match id {
AttrDefId::ModuleId(m) => {
m.def_map(db)[m.local_id].origin.file_id().map(Into::into)
}
AttrDefId::FunctionId(f) => Some(f.lookup(db).id.file_id()),
AttrDefId::StaticId(sid) => Some(sid.lookup(db).id.file_id()),
AttrDefId::ConstId(cid) => Some(cid.lookup(db).id.file_id()),
AttrDefId::TraitId(tid) => Some(tid.lookup(db).id.file_id()),
AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).id.file_id()),
AttrDefId::ImplId(iid) => Some(iid.lookup(db).id.file_id()),
AttrDefId::ExternBlockId(id) => Some(id.lookup(db).id.file_id()),
AttrDefId::ExternCrateId(id) => Some(id.lookup(db).id.file_id()),
AttrDefId::UseId(id) => Some(id.lookup(db).id.file_id()),
// These warnings should not explore macro definitions at all
AttrDefId::MacroId(_) => None,
AttrDefId::AdtId(aid) => match aid {
AdtId::StructId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
AdtId::EnumId(eid) => Some(eid.lookup(self.db.upcast()).container.into()),
AdtId::StructId(sid) => Some(sid.lookup(db).id.file_id()),
AdtId::EnumId(eid) => Some(eid.lookup(db).id.file_id()),
// Unions aren't yet supported
AdtId::UnionId(_) => None,
},
AttrDefId::FieldId(_) => None,
AttrDefId::EnumVariantId(_) => None,
AttrDefId::TypeAliasId(_) => None,
AttrDefId::GenericParamId(_) => None,
}
.map_or(false, |file_id| {
file_id.is_custom_derive(db.upcast()) || file_id.is_builtin_derive(db.upcast())
})
};
let parent = || {
match id {
AttrDefId::ModuleId(m) => m.containing_module(db).map(|v| v.into()),
AttrDefId::FunctionId(f) => Some(f.lookup(db).container.into()),
AttrDefId::StaticId(sid) => Some(sid.lookup(db).container.into()),
AttrDefId::ConstId(cid) => Some(cid.lookup(db).container.into()),
AttrDefId::TraitId(tid) => Some(tid.lookup(db).container.into()),
AttrDefId::TraitAliasId(taid) => Some(taid.lookup(db).container.into()),
AttrDefId::ImplId(iid) => Some(iid.lookup(db).container.into()),
AttrDefId::ExternBlockId(id) => Some(id.lookup(db).container.into()),
AttrDefId::ExternCrateId(id) => Some(id.lookup(db).container.into()),
AttrDefId::UseId(id) => Some(id.lookup(db).container.into()),
// These warnings should not explore macro definitions at all
AttrDefId::MacroId(_) => None,
AttrDefId::AdtId(aid) => match aid {
AdtId::StructId(sid) => Some(sid.lookup(db).container.into()),
AdtId::EnumId(eid) => Some(eid.lookup(db).container.into()),
// Unions aren't yet supported
AdtId::UnionId(_) => None,
},
@ -191,6 +222,12 @@ impl<'a> DeclValidator<'a> {
AttrDefId::GenericParamId(_) => None,
}
.is_some_and(|mid| self.allowed(mid, allow_name, true))
};
is_allowed(id)
// FIXME: this is a hack to avoid false positives in derive macros currently
|| file_id_is_derive()
// go upwards one step or give up
|| parent()
}
fn validate_func(&mut self, func: FunctionId) {

View file

@ -194,7 +194,8 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum InferenceDiagnostic {
NoSuchField {
expr: ExprId,
field: ExprOrPatId,
private: bool,
},
PrivateField {
expr: ExprId,
@ -228,6 +229,11 @@ pub enum InferenceDiagnostic {
expected: usize,
found: usize,
},
MismatchedTupleStructPatArgCount {
pat: ExprOrPatId,
expected: usize,
found: usize,
},
ExpectedFunction {
call_expr: ExprId,
found: Ty,

View file

@ -39,8 +39,14 @@ impl CastCheck {
}
fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool {
let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; };
let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; };
let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; };
let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else {
return false;
};
let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else {
return false;
};
let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else {
return false;
};
table.coerce(expr_elt_ty, cast_inner_ty).is_ok()
}

View file

@ -452,6 +452,8 @@ impl InferenceContext<'_> {
fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) {
match &self.body[tgt_expr] {
Expr::OffsetOf(_) => (),
Expr::InlineAsm(e) => self.walk_expr_without_adjust(e.e),
Expr::If { condition, then_branch, else_branch } => {
self.consume_expr(*condition);
self.consume_expr(*then_branch);
@ -467,13 +469,13 @@ impl InferenceContext<'_> {
Statement::Let { pat, type_ref: _, initializer, else_branch } => {
if let Some(else_branch) = else_branch {
self.consume_expr(*else_branch);
if let Some(initializer) = initializer {
self.consume_expr(*initializer);
}
return;
}
if let Some(initializer) = initializer {
self.walk_expr(*initializer);
if else_branch.is_some() {
self.consume_expr(*initializer);
} else {
self.walk_expr(*initializer);
}
if let Some(place) = self.place_of_expr(*initializer) {
self.consume_with_pat(place, *pat);
}
@ -620,6 +622,7 @@ impl InferenceContext<'_> {
| Expr::Tuple { exprs, is_assignee_expr: _ } => {
self.consume_exprs(exprs.iter().copied())
}
Expr::Missing
| Expr::Continue { .. }
| Expr::Path(_)

View file

@ -514,9 +514,6 @@ impl InferenceContext<'_> {
}
Expr::RecordLit { path, fields, spread, .. } => {
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
if let Some(variant) = def_id {
self.write_variant_resolution(tgt_expr.into(), variant);
}
if let Some(t) = expected.only_has_type(&mut self.table) {
self.unify(&ty, &t);
@ -526,26 +523,56 @@ impl InferenceContext<'_> {
.as_adt()
.map(|(_, s)| s.clone())
.unwrap_or_else(|| Substitution::empty(Interner));
let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
for field in fields.iter() {
let field_def =
variant_data.as_ref().and_then(|it| match it.field(&field.name) {
Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }),
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
expr: field.expr,
});
None
}
});
let field_ty = field_def.map_or(self.err_ty(), |it| {
field_types[it.local_id].clone().substitute(Interner, &substs)
});
// Field type might have some unknown types
// FIXME: we may want to emit a single type variable for all instance of type fields?
let field_ty = self.insert_type_vars(field_ty);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
if let Some(variant) = def_id {
self.write_variant_resolution(tgt_expr.into(), variant);
}
match def_id {
_ if fields.is_empty() => {}
Some(def) => {
let field_types = self.db.field_types(def);
let variant_data = def.variant_data(self.db.upcast());
let visibilities = self.db.field_visibilities(def);
for field in fields.iter() {
let field_def = {
match variant_data.field(&field.name) {
Some(local_id) => {
if !visibilities[local_id].is_visible_from(
self.db.upcast(),
self.resolver.module(),
) {
self.push_diagnostic(
InferenceDiagnostic::NoSuchField {
field: field.expr.into(),
private: true,
},
);
}
Some(local_id)
}
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: field.expr.into(),
private: false,
});
None
}
}
};
let field_ty = field_def.map_or(self.err_ty(), |it| {
field_types[it].clone().substitute(Interner, &substs)
});
// Field type might have some unknown types
// FIXME: we may want to emit a single type variable for all instance of type fields?
let field_ty = self.insert_type_vars(field_ty);
self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
}
}
None => {
for field in fields.iter() {
self.infer_expr_coerce(field.expr, &Expectation::None);
}
}
}
if let Some(expr) = spread {
self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
@ -843,6 +870,11 @@ impl InferenceContext<'_> {
});
expected
}
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
Expr::InlineAsm(it) => {
self.infer_expr_no_expect(it.e);
self.result.standard_types.unit.clone()
}
};
// use a new type variable if we got unknown here
let ty = self.insert_type_vars_shallow(ty);
@ -1122,7 +1154,7 @@ impl InferenceContext<'_> {
Expr::Underscore => rhs_ty.clone(),
_ => {
// `lhs` is a place expression, a unit struct, or an enum variant.
let lhs_ty = self.infer_expr(lhs, &Expectation::none());
let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none());
// This is the only branch where this function may coerce any type.
// We are returning early to avoid the unifiability check below.

View file

@ -35,6 +35,8 @@ impl InferenceContext<'_> {
fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
match &self.body[tgt_expr] {
Expr::Missing => (),
Expr::InlineAsm(e) => self.infer_mut_expr_without_adjust(e.e, Mutability::Not),
Expr::OffsetOf(_) => (),
&Expr::If { condition, then_branch, else_branch } => {
self.infer_mut_expr(condition, Mutability::Not);
self.infer_mut_expr(then_branch, Mutability::Not);

View file

@ -15,7 +15,8 @@ use crate::{
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
lower::lower_to_chalk_mutability,
primitive::UintTy,
static_lifetime, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt, TyKind,
static_lifetime, InferenceDiagnostic, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt,
TyKind,
};
/// Used to generalize patterns and assignee expressions.
@ -74,29 +75,68 @@ impl InferenceContext<'_> {
if let Some(variant) = def {
self.write_variant_resolution(id.into(), variant);
}
if let Some(var) = &var_data {
let cmp = if ellipsis.is_some() { usize::gt } else { usize::ne };
if cmp(&subs.len(), &var.fields().len()) {
self.push_diagnostic(InferenceDiagnostic::MismatchedTupleStructPatArgCount {
pat: id.into(),
expected: var.fields().len(),
found: subs.len(),
});
}
}
self.unify(&ty, expected);
let substs =
ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
let (pre, post) = match ellipsis {
Some(idx) => subs.split_at(idx),
None => (subs, &[][..]),
};
let post_idx_offset = field_tys.iter().count().saturating_sub(post.len());
match def {
_ if subs.len() == 0 => {}
Some(def) => {
let field_types = self.db.field_types(def);
let variant_data = def.variant_data(self.db.upcast());
let visibilities = self.db.field_visibilities(def);
let pre_iter = pre.iter().enumerate();
let post_iter = (post_idx_offset..).zip(post.iter());
for (i, &subpat) in pre_iter.chain(post_iter) {
let expected_ty = var_data
.as_ref()
.and_then(|d| d.field(&Name::new_tuple_field(i)))
.map_or(self.err_ty(), |field| {
field_tys[field].clone().substitute(Interner, &substs)
});
let expected_ty = self.normalize_associated_types_in(expected_ty);
T::infer(self, subpat, &expected_ty, default_bm);
let (pre, post) = match ellipsis {
Some(idx) => subs.split_at(idx),
None => (subs, &[][..]),
};
let post_idx_offset = field_types.iter().count().saturating_sub(post.len());
let pre_iter = pre.iter().enumerate();
let post_iter = (post_idx_offset..).zip(post.iter());
for (i, &subpat) in pre_iter.chain(post_iter) {
let field_def = {
match variant_data.field(&Name::new_tuple_field(i)) {
Some(local_id) => {
if !visibilities[local_id]
.is_visible_from(self.db.upcast(), self.resolver.module())
{
// FIXME(DIAGNOSE): private tuple field
}
Some(local_id)
}
None => None,
}
};
let expected_ty = field_def.map_or(self.err_ty(), |f| {
field_types[f].clone().substitute(Interner, &substs)
});
let expected_ty = self.normalize_associated_types_in(expected_ty);
T::infer(self, subpat, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for &inner in subs {
T::infer(self, inner, &err_ty, default_bm);
}
}
}
ty
@ -109,7 +149,7 @@ impl InferenceContext<'_> {
expected: &Ty,
default_bm: T::BindingMode,
id: T,
subs: impl Iterator<Item = (Name, T)>,
subs: impl Iterator<Item = (Name, T)> + ExactSizeIterator,
) -> Ty {
let (ty, def) = self.resolve_variant(path, false);
if let Some(variant) = def {
@ -121,17 +161,51 @@ impl InferenceContext<'_> {
let substs =
ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
match def {
_ if subs.len() == 0 => {}
Some(def) => {
let field_types = self.db.field_types(def);
let variant_data = def.variant_data(self.db.upcast());
let visibilities = self.db.field_visibilities(def);
for (name, inner) in subs {
let expected_ty = var_data
.as_ref()
.and_then(|it| it.field(&name))
.map_or(self.err_ty(), |f| field_tys[f].clone().substitute(Interner, &substs));
let expected_ty = self.normalize_associated_types_in(expected_ty);
for (name, inner) in subs {
let field_def = {
match variant_data.field(&name) {
Some(local_id) => {
if !visibilities[local_id]
.is_visible_from(self.db.upcast(), self.resolver.module())
{
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: inner.into(),
private: true,
});
}
Some(local_id)
}
None => {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: inner.into(),
private: false,
});
None
}
}
};
T::infer(self, inner, &expected_ty, default_bm);
let expected_ty = field_def.map_or(self.err_ty(), |f| {
field_types[f].clone().substitute(Interner, &substs)
});
let expected_ty = self.normalize_associated_types_in(expected_ty);
T::infer(self, inner, &expected_ty, default_bm);
}
}
None => {
let err_ty = self.err_ty();
for (_, inner) in subs {
T::infer(self, inner, &err_ty, default_bm);
}
}
}
ty

View file

@ -178,13 +178,30 @@ impl InferenceContext<'_> {
remaining_index: usize,
id: ExprOrPatId,
) -> Option<(ValueNs, Substitution)> {
assert!(remaining_index < path.segments().len());
// there may be more intermediate segments between the resolved one and
// the end. Only the last segment needs to be resolved to a value; from
// the segments before that, we need to get either a type or a trait ref.
let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
let remaining_segments = path.segments().skip(remaining_index);
let _d;
let (resolved_segment, remaining_segments) = match path {
Path::Normal { .. } => {
assert!(remaining_index < path.segments().len());
(
path.segments().get(remaining_index - 1).unwrap(),
path.segments().skip(remaining_index),
)
}
Path::LangItem(..) => (
PathSegment {
name: {
_d = hir_expand::name::known::Unknown;
&_d
},
args_and_bindings: None,
},
path.segments(),
),
};
let is_before_last = remaining_segments.len() == 1;
match (def, is_before_last) {

View file

@ -24,7 +24,7 @@ pub use self::{
macro_rules! user_error {
($it: expr) => {
return Err(LayoutError::UserError(format!($it)))
return Err(LayoutError::UserError(format!($it).into()))
};
}
@ -50,7 +50,7 @@ pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum LayoutError {
UserError(String),
UserError(Box<str>),
SizeOverflow,
TargetLayoutNotAvailable,
HasPlaceholder,
@ -109,7 +109,8 @@ fn layout_of_simd_ty(
// * the homogeneous field type and the number of fields.
let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
// Extract the number of elements from the layout of the array field:
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else {
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields
else {
user_error!("Array with non array layout");
};
@ -233,9 +234,9 @@ pub fn layout_of_ty_query(
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
}
TyKind::Array(element, count) => {
let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
"unevaluated or mistyped const generic parameter".to_string(),
))? as u64;
let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(Box::from(
"unevaluated or mistyped const generic parameter",
)))? as u64;
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;

View file

@ -163,7 +163,7 @@ fn repr_discr(
return Err(LayoutError::UserError(
"Integer::repr_discr: `#[repr]` hint too small for \
discriminant range of enum "
.to_string(),
.into(),
));
}
return Ok((discr, ity.is_signed()));

View file

@ -212,14 +212,14 @@ fn recursive() {
}
check_fail(
r#"struct Goal(Goal);"#,
LayoutError::UserError("infinite sized recursive type".to_string()),
LayoutError::UserError("infinite sized recursive type".into()),
);
check_fail(
r#"
struct Foo<T>(Foo<T>);
struct Goal(Foo<i32>);
"#,
LayoutError::UserError("infinite sized recursive type".to_string()),
LayoutError::UserError("infinite sized recursive type".into()),
);
}

View file

@ -255,3 +255,17 @@ fn ellipsis_pattern() {
}
}
}
#[test]
fn regression_15623() {
size_and_align_expr! {
let a = 2;
let b = 3;
let c = 5;
move || {
let 0 = a else { return b; };
let y = c;
y
}
}
}

View file

@ -1,6 +1,6 @@
//! MIR definitions and implementation
use std::{fmt::Display, iter};
use std::{collections::hash_map::Entry, fmt::Display, iter};
use crate::{
consteval::usize_const,
@ -37,6 +37,7 @@ pub use monomorphization::{
monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
monomorphized_mir_body_query, monomorphized_mir_body_recover,
};
use rustc_hash::FxHashMap;
use smallvec::{smallvec, SmallVec};
use stdx::{impl_from, never};
use triomphe::Arc;
@ -165,8 +166,8 @@ impl<V, T> ProjectionElem<V, T> {
TyKind::Adt(_, subst) => {
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
}
_ => {
never!("Only adt has field");
ty => {
never!("Only adt has field, found {:?}", ty);
return TyKind::Error.intern(Interner);
}
},
@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
type PlaceElem = ProjectionElem<LocalId, Ty>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProjectionId(u32);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProjectionStore {
id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
}
impl Default for ProjectionStore {
fn default() -> Self {
let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
// Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
this.intern(Box::new([]));
this
}
}
impl ProjectionStore {
fn shrink_to_fit(&mut self) {
self.id_to_proj.shrink_to_fit();
self.proj_to_id.shrink_to_fit();
}
fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
self.proj_to_id.get(projection).copied()
}
fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
let new_id = ProjectionId(self.proj_to_id.len() as u32);
match self.proj_to_id.entry(projection) {
Entry::Occupied(id) => *id.get(),
Entry::Vacant(e) => {
let key_clone = e.key().clone();
e.insert(new_id);
self.id_to_proj.insert(new_id, key_clone);
new_id
}
}
}
}
impl ProjectionId {
const EMPTY: ProjectionId = ProjectionId(0);
fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
store.id_to_proj.get(&self).unwrap()
}
fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
let mut current = self.lookup(store).to_vec();
current.push(projection);
store.intern(current.into())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Place {
pub local: LocalId,
pub projection: Box<[PlaceElem]>,
pub projection: ProjectionId,
}
impl Place {
fn is_parent(&self, child: &Place) -> bool {
self.local == child.local && child.projection.starts_with(&self.projection)
fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
self.local == child.local
&& child.projection.lookup(store).starts_with(&self.projection.lookup(store))
}
/// The place itself is not included
fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ {
(0..self.projection.len())
.map(|x| &self.projection[0..x])
.map(|x| Place { local: self.local, projection: x.to_vec().into() })
fn iterate_over_parents<'a>(
&'a self,
store: &'a ProjectionStore,
) -> impl Iterator<Item = Place> + 'a {
let projection = self.projection.lookup(store);
(0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
})
}
fn project(&self, projection: PlaceElem) -> Place {
Place {
local: self.local,
projection: self.projection.iter().cloned().chain([projection]).collect(),
}
fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
Place { local: self.local, projection: self.projection.project(projection, store) }
}
}
impl From<LocalId> for Place {
fn from(local: LocalId) -> Self {
Self { local, projection: vec![].into() }
Self { local, projection: ProjectionId::EMPTY }
}
}
@ -997,6 +1056,7 @@ pub struct BasicBlock {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MirBody {
pub projection_store: ProjectionStore,
pub basic_blocks: Arena<BasicBlock>,
pub locals: Arena<Local>,
pub start_block: BasicBlockId,
@ -1009,11 +1069,15 @@ pub struct MirBody {
}
impl MirBody {
fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) {
fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) {
fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
fn for_operand(
op: &mut Operand,
f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
store: &mut ProjectionStore,
) {
match op {
Operand::Copy(p) | Operand::Move(p) => {
f(p);
f(p, store);
}
Operand::Constant(_) | Operand::Static(_) => (),
}
@ -1022,30 +1086,30 @@ impl MirBody {
for statement in &mut block.statements {
match &mut statement.kind {
StatementKind::Assign(p, r) => {
f(p);
f(p, &mut self.projection_store);
match r {
Rvalue::ShallowInitBoxWithAlloc(_) => (),
Rvalue::ShallowInitBox(o, _)
| Rvalue::UnaryOp(_, o)
| Rvalue::Cast(_, o, _)
| Rvalue::Repeat(o, _)
| Rvalue::Use(o) => for_operand(o, &mut f),
| Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
Rvalue::CopyForDeref(p)
| Rvalue::Discriminant(p)
| Rvalue::Len(p)
| Rvalue::Ref(_, p) => f(p),
| Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
Rvalue::CheckedBinaryOp(_, o1, o2) => {
for_operand(o1, &mut f);
for_operand(o2, &mut f);
for_operand(o1, &mut f, &mut self.projection_store);
for_operand(o2, &mut f, &mut self.projection_store);
}
Rvalue::Aggregate(_, ops) => {
for op in ops.iter_mut() {
for_operand(op, &mut f);
for_operand(op, &mut f, &mut self.projection_store);
}
}
}
}
StatementKind::Deinit(p) => f(p),
StatementKind::Deinit(p) => f(p, &mut self.projection_store),
StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Nop => (),
@ -1053,7 +1117,9 @@ impl MirBody {
}
match &mut block.terminator {
Some(x) => match &mut x.kind {
TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f),
TerminatorKind::SwitchInt { discr, .. } => {
for_operand(discr, &mut f, &mut self.projection_store)
}
TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }
@ -1063,23 +1129,24 @@ impl MirBody {
| TerminatorKind::Return
| TerminatorKind::Unreachable => (),
TerminatorKind::Drop { place, .. } => {
f(place);
f(place, &mut self.projection_store);
}
TerminatorKind::DropAndReplace { place, value, .. } => {
f(place);
for_operand(value, &mut f);
f(place, &mut self.projection_store);
for_operand(value, &mut f, &mut self.projection_store);
}
TerminatorKind::Call { func, args, destination, .. } => {
for_operand(func, &mut f);
args.iter_mut().for_each(|x| for_operand(x, &mut f));
f(destination);
for_operand(func, &mut f, &mut self.projection_store);
args.iter_mut()
.for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
f(destination, &mut self.projection_store);
}
TerminatorKind::Assert { cond, .. } => {
for_operand(cond, &mut f);
for_operand(cond, &mut f, &mut self.projection_store);
}
TerminatorKind::Yield { value, resume_arg, .. } => {
for_operand(value, &mut f);
f(resume_arg);
for_operand(value, &mut f, &mut self.projection_store);
f(resume_arg, &mut self.projection_store);
}
},
None => (),
@ -1096,7 +1163,9 @@ impl MirBody {
binding_locals,
param_locals,
closures,
projection_store,
} = self;
projection_store.shrink_to_fit();
basic_blocks.shrink_to_fit();
locals.shrink_to_fit();
binding_locals.shrink_to_fit();

View file

@ -42,30 +42,27 @@ pub struct BorrowckResult {
fn all_mir_bodies(
db: &dyn HirDatabase,
def: DefWithBodyId,
) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
mut cb: impl FnMut(Arc<MirBody>),
) -> Result<(), MirLowerError> {
fn for_closure(
db: &dyn HirDatabase,
c: ClosureId,
) -> Box<dyn Iterator<Item = Result<Arc<MirBody>, MirLowerError>> + '_> {
cb: &mut impl FnMut(Arc<MirBody>),
) -> Result<(), MirLowerError> {
match db.mir_body_for_closure(c) {
Ok(body) => {
let closures = body.closures.clone();
Box::new(
iter::once(Ok(body))
.chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
)
cb(body.clone());
body.closures.iter().map(|&it| for_closure(db, it, cb)).collect()
}
Err(e) => Box::new(iter::once(Err(e))),
Err(e) => Err(e),
}
}
match db.mir_body(def) {
Ok(body) => {
let closures = body.closures.clone();
Box::new(
iter::once(Ok(body)).chain(closures.into_iter().flat_map(|it| for_closure(db, it))),
)
cb(body.clone());
body.closures.iter().map(|&it| for_closure(db, it, &mut cb)).collect()
}
Err(e) => Box::new(iter::once(Err(e))),
Err(e) => Err(e),
}
}
@ -74,17 +71,15 @@ pub fn borrowck_query(
def: DefWithBodyId,
) -> Result<Arc<[BorrowckResult]>, MirLowerError> {
let _p = profile::span("borrowck_query");
let r = all_mir_bodies(db, def)
.map(|body| {
let body = body?;
Ok(BorrowckResult {
mutability_of_locals: mutability_of_locals(db, &body),
moved_out_of_ref: moved_out_of_ref(db, &body),
mir_body: body,
})
})
.collect::<Result<Vec<_>, MirLowerError>>()?;
Ok(r.into())
let mut res = vec![];
all_mir_bodies(db, def, |body| {
res.push(BorrowckResult {
mutability_of_locals: mutability_of_locals(db, &body),
moved_out_of_ref: moved_out_of_ref(db, &body),
mir_body: body,
});
})?;
Ok(res.into())
}
fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
@ -93,7 +88,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
Operand::Copy(p) | Operand::Move(p) => {
let mut ty: Ty = body.locals[p.local].ty.clone();
let mut is_dereference_of_ref = false;
for proj in &*p.projection {
for proj in p.projection.lookup(&body.projection_store) {
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
is_dereference_of_ref = true;
}
@ -125,6 +120,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
Operand::Constant(_) | Operand::Static(_) => (),
};
for (_, block) in body.basic_blocks.iter() {
db.unwind_if_cancelled();
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(_, r) => match r {
@ -183,6 +179,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
None => (),
}
}
result.shrink_to_fit();
result
}
@ -199,7 +196,7 @@ enum ProjectionCase {
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
let mut is_part_of = false;
let mut ty = body.locals[lvalue.local].ty.clone();
for proj in lvalue.projection.iter() {
for proj in lvalue.projection.lookup(&body.projection_store).iter() {
match proj {
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
ProjectionElem::Deref // It's direct in case of `Box<T>`
@ -258,7 +255,7 @@ fn ever_initialized_map(
for statement in &block.statements {
match &statement.kind {
StatementKind::Assign(p, _) => {
if p.projection.len() == 0 && p.local == l {
if p.projection.lookup(&body.projection_store).len() == 0 && p.local == l {
is_ever_initialized = true;
}
}
@ -277,21 +274,37 @@ fn ever_initialized_map(
);
return;
};
let targets = match &terminator.kind {
TerminatorKind::Goto { target } => vec![*target],
TerminatorKind::SwitchInt { targets, .. } => targets.all_targets().to_vec(),
let mut process = |target, is_ever_initialized| {
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
result[target].insert(l, is_ever_initialized);
dfs(db, body, target, l, result);
}
};
match &terminator.kind {
TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
TerminatorKind::SwitchInt { targets, .. } => {
targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
}
TerminatorKind::UnwindResume
| TerminatorKind::Abort
| TerminatorKind::Return
| TerminatorKind::Unreachable => vec![],
| TerminatorKind::Unreachable => (),
TerminatorKind::Call { target, cleanup, destination, .. } => {
if destination.projection.len() == 0 && destination.local == l {
if destination.projection.lookup(&body.projection_store).len() == 0
&& destination.local == l
{
is_ever_initialized = true;
}
target.into_iter().chain(cleanup.into_iter()).copied().collect()
target
.into_iter()
.chain(cleanup.into_iter())
.for_each(|&it| process(it, is_ever_initialized));
}
TerminatorKind::Drop { target, unwind, place: _ } => {
Some(target).into_iter().chain(unwind.into_iter()).copied().collect()
iter::once(target)
.into_iter()
.chain(unwind.into_iter())
.for_each(|&it| process(it, is_ever_initialized));
}
TerminatorKind::DropAndReplace { .. }
| TerminatorKind::Assert { .. }
@ -300,13 +313,7 @@ fn ever_initialized_map(
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. } => {
never!("We don't emit these MIR terminators yet");
vec![]
}
};
for target in targets {
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
result[target].insert(l, is_ever_initialized);
dfs(db, body, target, l, result);
()
}
}
}
@ -315,6 +322,7 @@ fn ever_initialized_map(
dfs(db, body, body.start_block, l, &mut result);
}
for l in body.locals.iter().map(|it| it.0) {
db.unwind_if_cancelled();
if !result[body.start_block].contains_idx(l) {
result[body.start_block].insert(l, false);
dfs(db, body, body.start_block, l, &mut result);
@ -384,7 +392,7 @@ fn mutability_of_locals(
| TerminatorKind::Assert { .. }
| TerminatorKind::Yield { .. } => (),
TerminatorKind::Call { destination, .. } => {
if destination.projection.len() == 0 {
if destination.projection.lookup(&body.projection_store).len() == 0 {
if ever_init_map.get(destination.local).copied().unwrap_or_default() {
push_mut_span(destination.local, MirSpan::Unknown);
} else {

View file

@ -46,8 +46,8 @@ use crate::{
use super::{
return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind,
UnOp,
MirSpan, Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind,
TerminatorKind, UnOp,
};
mod shim;
@ -215,9 +215,7 @@ impl Interval {
}
fn write_from_interval(&self, memory: &mut Evaluator<'_>, interval: Interval) -> Result<()> {
// FIXME: this could be more efficient
let bytes = &interval.get(memory)?.to_vec();
memory.write_memory(self.addr, bytes)
memory.copy_from_interval(self.addr, interval)
}
fn slice(self, range: Range<usize>) -> Interval {
@ -341,7 +339,7 @@ pub enum MirEvalError {
InvalidVTableId(usize),
CoerceUnsizedError(Ty),
LangItemNotFound(LangItem),
BrokenLayout(Layout),
BrokenLayout(Box<Layout>),
}
impl MirEvalError {
@ -410,7 +408,7 @@ impl MirEvalError {
err.pretty_print(f, db, span_formatter)?;
}
MirEvalError::ConstEvalError(name, err) => {
MirLowerError::ConstEvalError(name.clone(), err.clone()).pretty_print(
MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print(
f,
db,
span_formatter,
@ -485,17 +483,18 @@ struct DropFlags {
}
impl DropFlags {
fn add_place(&mut self, p: Place) {
if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {
fn add_place(&mut self, p: Place, store: &ProjectionStore) {
if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) {
return;
}
self.need_drop.retain(|it| !p.is_parent(it));
self.need_drop.retain(|it| !p.is_parent(it, store));
self.need_drop.insert(p);
}
fn remove_place(&mut self, p: &Place) -> bool {
fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool {
// FIXME: replace parents with parts
if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) {
if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(&it))
{
self.need_drop.remove(&parent);
return true;
}
@ -656,7 +655,7 @@ impl Evaluator<'_> {
let mut addr = locals.ptr[p.local].addr;
let mut ty: Ty = locals.body.locals[p.local].ty.clone();
let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
for proj in &*p.projection {
for proj in p.projection.lookup(&locals.body.projection_store) {
let prev_ty = ty.clone();
ty = self.projected_ty(ty, proj.clone());
match proj {
@ -837,7 +836,9 @@ impl Evaluator<'_> {
let addr = self.place_addr(l, &locals)?;
let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
self.write_memory(addr, &result)?;
locals.drop_flags.add_place(l.clone());
locals
.drop_flags
.add_place(l.clone(), &locals.body.projection_store);
}
StatementKind::Deinit(_) => not_supported!("de-init statement"),
StatementKind::StorageLive(_)
@ -889,7 +890,9 @@ impl Evaluator<'_> {
)?,
it => not_supported!("unknown function type {it:?}"),
};
locals.drop_flags.add_place(destination.clone());
locals
.drop_flags
.add_place(destination.clone(), &locals.body.projection_store);
if let Some(stack_frame) = stack_frame {
self.code_stack.push(my_stack_frame);
current_block_idx = stack_frame.locals.body.start_block;
@ -970,7 +973,7 @@ impl Evaluator<'_> {
) -> Result<()> {
let mut remain_args = body.param_locals.len();
for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
locals.drop_flags.add_place(l.into());
locals.drop_flags.add_place(l.into(), &locals.body.projection_store);
match value {
IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
@ -1629,7 +1632,7 @@ impl Evaluator<'_> {
if let Some((offset, size, value)) = tag {
match result.get_mut(offset..offset + size) {
Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
}
}
for (i, op) in values.enumerate() {
@ -1637,7 +1640,7 @@ impl Evaluator<'_> {
let op = op.get(&self)?;
match result.get_mut(offset..offset + op.len()) {
Some(it) => it.copy_from_slice(op),
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
None => return Err(MirEvalError::BrokenLayout(Box::new(variant_layout.clone()))),
}
}
Ok(result)
@ -1646,7 +1649,7 @@ impl Evaluator<'_> {
fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<Interval> {
Ok(match it {
Operand::Copy(p) | Operand::Move(p) => {
locals.drop_flags.remove_place(p);
locals.drop_flags.remove_place(p, &locals.body.projection_store);
self.eval_place(p, locals)?
}
Operand::Static(st) => {
@ -1760,6 +1763,48 @@ impl Evaluator<'_> {
Ok(())
}
fn copy_from_interval(&mut self, addr: Address, r: Interval) -> Result<()> {
if r.size == 0 {
return Ok(());
}
let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_string());
match (addr, r.addr) {
(Stack(dst), Stack(src)) => {
if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
return Err(oob());
}
self.stack.copy_within(src..src + r.size, dst)
}
(Heap(dst), Heap(src)) => {
if self.stack.len() < src + r.size || self.stack.len() < dst + r.size {
return Err(oob());
}
self.heap.copy_within(src..src + r.size, dst)
}
(Stack(dst), Heap(src)) => {
self.stack
.get_mut(dst..dst + r.size)
.ok_or_else(oob)?
.copy_from_slice(self.heap.get(src..src + r.size).ok_or_else(oob)?);
}
(Heap(dst), Stack(src)) => {
self.heap
.get_mut(dst..dst + r.size)
.ok_or_else(oob)?
.copy_from_slice(self.stack.get(src..src + r.size).ok_or_else(oob)?);
}
_ => {
return Err(MirEvalError::UndefinedBehavior(format!(
"invalid memory write at address {addr:?}"
)))
}
}
Ok(())
}
fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> {
if let Some(layout) = self.layout_cache.borrow().get(ty) {
return Ok(layout
@ -2468,7 +2513,7 @@ impl Evaluator<'_> {
fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> {
let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
if !locals.drop_flags.remove_place(place) {
if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
return Ok(());
}
let metadata = match metadata {

View file

@ -4,7 +4,10 @@
use std::cmp;
use chalk_ir::TyKind;
use hir_def::resolver::HasResolver;
use hir_def::{
builtin_type::{BuiltinInt, BuiltinUint},
resolver::HasResolver,
};
use hir_expand::mod_path::ModPath;
use super::*;
@ -300,21 +303,36 @@ impl Evaluator<'_> {
BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_string())),
PanicFmt => {
let message = (|| {
let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db.upcast());
let resolver = self
.db
.crate_def_map(self.crate_id)
.crate_root()
.resolver(self.db.upcast());
let Some(format_fn) = resolver.resolve_path_in_value_ns_fully(
self.db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments(
hir_expand::mod_path::PathKind::Abs,
[name![std], name![fmt], name![format]].into_iter(),
)),
&hir_def::path::Path::from_known_path_with_no_generic(
ModPath::from_segments(
hir_expand::mod_path::PathKind::Abs,
[name![std], name![fmt], name![format]].into_iter(),
),
),
) else {
not_supported!("std::fmt::format not found");
};
let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") };
let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?;
let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else {
not_supported!("std::fmt::format is not a function")
};
let message_string = self.interpret_mir(
self.db
.mir_body(format_fn.into())
.map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
args.map(|x| IntervalOrOwned::Owned(x.clone())),
)?;
let addr =
Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned())
Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?)
.into_owned())
})()
.unwrap_or_else(|e| format!("Failed to render panic format args: {e:?}"));
Err(MirEvalError::Panic(message))
@ -483,9 +501,7 @@ impl Evaluator<'_> {
}
"syscall" => {
let Some((id, rest)) = args.split_first() else {
return Err(MirEvalError::TypeError(
"syscall arg1 is not provided",
));
return Err(MirEvalError::TypeError("syscall arg1 is not provided"));
};
let id = from_bytes!(i64, id.get(self)?);
self.exec_syscall(id, rest, destination, locals, span)
@ -710,7 +726,8 @@ impl Evaluator<'_> {
}
match name {
"size_of" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
};
@ -718,14 +735,17 @@ impl Evaluator<'_> {
destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
}
"min_align_of" | "pref_align_of" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("align_of generic arg is not provided"));
};
let align = self.layout(ty)?.align.abi.bytes();
destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
}
"size_of_val" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of_val generic arg is not provided"));
};
@ -741,8 +761,12 @@ impl Evaluator<'_> {
}
}
"min_align_of_val" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
return Err(MirEvalError::TypeError("min_align_of_val generic arg is not provided"));
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"min_align_of_val generic arg is not provided",
));
};
let [arg] = args else {
return Err(MirEvalError::TypeError("min_align_of_val args are not provided"));
@ -756,7 +780,8 @@ impl Evaluator<'_> {
}
}
"type_name" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("type_name generic arg is not provided"));
};
@ -779,7 +804,8 @@ impl Evaluator<'_> {
.write_from_bytes(self, &len.to_le_bytes())
}
"needs_drop" => {
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("size_of generic arg is not provided"));
};
@ -831,9 +857,12 @@ impl Evaluator<'_> {
let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false));
let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false));
let ans = lhs.wrapping_sub(rhs);
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("ptr_offset_from generic arg is not provided"));
return Err(MirEvalError::TypeError(
"ptr_offset_from generic arg is not provided",
));
};
let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128;
let ans = ans / size;
@ -940,7 +969,8 @@ impl Evaluator<'_> {
"copy_nonoverlapping args are not provided",
));
};
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"copy_nonoverlapping generic arg is not provided",
@ -959,9 +989,45 @@ impl Evaluator<'_> {
let [ptr, offset] = args else {
return Err(MirEvalError::TypeError("offset args are not provided"));
};
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("offset generic arg is not provided"));
let ty = if name == "offset" {
let Some(ty0) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("offset generic arg is not provided"));
};
let Some(ty1) =
generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("offset generic arg is not provided"));
};
if !matches!(
ty1.as_builtin(),
Some(
BuiltinType::Int(BuiltinInt::Isize)
| BuiltinType::Uint(BuiltinUint::Usize)
)
) {
return Err(MirEvalError::TypeError(
"offset generic arg is not usize or isize",
));
}
match ty0.as_raw_ptr() {
Some((ty, _)) => ty,
None => {
return Err(MirEvalError::TypeError(
"offset generic arg is not a raw pointer",
));
}
}
} else {
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"arith_offset generic arg is not provided",
));
};
ty
};
let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false));
let offset = u128::from_le_bytes(pad16(offset.get(self)?, false));
@ -1079,7 +1145,8 @@ impl Evaluator<'_> {
let [arg] = args else {
return Err(MirEvalError::TypeError("discriminant_value arg is not provided"));
};
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"discriminant_value generic arg is not provided",
@ -1133,17 +1200,32 @@ impl Evaluator<'_> {
let addr = Address::from_bytes(arg.interval.get(self)?)?;
destination.write_from_interval(self, Interval { addr, size: destination.size })
}
"write_via_move" => {
let [ptr, val] = args else {
return Err(MirEvalError::TypeError("write_via_move args are not provided"));
};
let dst = Address::from_bytes(ptr.get(self)?)?;
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"write_via_copy generic arg is not provided",
));
};
let size = self.size_of_sized(ty, locals, "write_via_move ptr type")?;
Interval { addr: dst, size }.write_from_interval(self, val.interval)?;
Ok(())
}
"write_bytes" => {
let [dst, val, count] = args else {
return Err(MirEvalError::TypeError("write_bytes args are not provided"));
};
let count = from_bytes!(usize, count.get(self)?);
let val = from_bytes!(u8, val.get(self)?);
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
let Some(ty) =
generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError(
"write_bytes generic arg is not provided",
));
return Err(MirEvalError::TypeError("write_bytes generic arg is not provided"));
};
let dst = Address::from_bytes(dst.get(self)?)?;
let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;

View file

@ -45,7 +45,9 @@ impl Evaluator<'_> {
};
match try_const_usize(self.db, len) {
Some(len) => {
let Some(ty) = subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
let Some(ty) =
subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
else {
return Err(MirEvalError::TypeError("simd type with no ty param"));
};
Ok((len as usize, ty.clone()))

View file

@ -71,7 +71,7 @@ struct MirLowerCtx<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MirLowerError {
ConstEvalError(String, Box<ConstEvalError>),
ConstEvalError(Box<str>, Box<ConstEvalError>),
LayoutError(LayoutError),
IncompleteExpr,
IncompletePattern,
@ -84,7 +84,7 @@ pub enum MirLowerError {
UnsizedTemporary(Ty),
MissingFunctionDefinition(DefWithBodyId, ExprId),
TypeMismatch(TypeMismatch),
/// This should be never happen. Type mismatch should catch everything.
/// This should never happen. Type mismatch should catch everything.
TypeError(&'static str),
NotSupported(String),
ContinueWithoutLoop,
@ -244,6 +244,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let locals = Arena::new();
let binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
let mir = MirBody {
projection_store: ProjectionStore::default(),
basic_blocks,
locals,
start_block,
@ -370,6 +371,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
mut current: BasicBlockId,
) -> Result<Option<BasicBlockId>> {
match &self.body.exprs[expr_id] {
Expr::OffsetOf(_) => {
not_supported!("builtin#offset_of")
}
Expr::InlineAsm(_) => {
not_supported!("builtin#asm")
}
Expr::Missing => {
if let DefWithBodyId::FunctionId(f) = self.owner {
let assoc = f.lookup(self.db.upcast());
@ -803,36 +810,34 @@ impl<'ctx> MirLowerCtx<'ctx> {
current = c;
operands[u32::from(field_id.into_raw()) as usize] = Some(op);
}
self.push_assignment(
current,
place,
Rvalue::Aggregate(
AggregateKind::Adt(variant_id, subst),
match spread_place {
Some(sp) => operands
.into_iter()
.enumerate()
.map(|(i, it)| match it {
Some(it) => it,
None => {
let p =
sp.project(ProjectionElem::Field(FieldId {
parent: variant_id,
local_id: LocalFieldId::from_raw(
RawIdx::from(i as u32),
),
}));
Operand::Copy(p)
}
})
.collect(),
None => operands.into_iter().collect::<Option<_>>().ok_or(
MirLowerError::TypeError("missing field in record literal"),
)?,
},
),
expr_id.into(),
let rvalue = Rvalue::Aggregate(
AggregateKind::Adt(variant_id, subst),
match spread_place {
Some(sp) => operands
.into_iter()
.enumerate()
.map(|(i, it)| match it {
Some(it) => it,
None => {
let p = sp.project(
ProjectionElem::Field(FieldId {
parent: variant_id,
local_id: LocalFieldId::from_raw(RawIdx::from(
i as u32,
)),
}),
&mut self.result.projection_store,
);
Operand::Copy(p)
}
})
.collect(),
None => operands.into_iter().collect::<Option<_>>().ok_or(
MirLowerError::TypeError("missing field in record literal"),
)?,
},
);
self.push_assignment(current, place, rvalue, expr_id.into());
Ok(Some(current))
}
VariantId::UnionId(union_id) => {
@ -841,10 +846,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
let local_id =
variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
let place = place.project(PlaceElem::Field(FieldId {
parent: union_id.into(),
local_id,
}));
let place = place.project(
PlaceElem::Field(FieldId { parent: union_id.into(), local_id }),
&mut self.result.projection_store,
);
self.lower_expr_to_place(*expr, place, current)
}
}
@ -898,7 +903,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
let p = place.project(ProjectionElem::Deref);
let p = place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.push_assignment(current, p, operand.into(), expr_id.into());
Ok(Some(current))
}
@ -1120,27 +1125,31 @@ impl<'ctx> MirLowerCtx<'ctx> {
for capture in captures.iter() {
let p = Place {
local: self.binding_local(capture.place.local)?,
projection: capture
.place
.projections
.clone()
.into_iter()
.map(|it| match it {
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(it) => ProjectionElem::Field(it),
ProjectionElem::TupleOrClosureField(it) => {
ProjectionElem::TupleOrClosureField(it)
}
ProjectionElem::ConstantIndex { offset, from_end } => {
ProjectionElem::ConstantIndex { offset, from_end }
}
ProjectionElem::Subslice { from, to } => {
ProjectionElem::Subslice { from, to }
}
ProjectionElem::OpaqueCast(it) => ProjectionElem::OpaqueCast(it),
ProjectionElem::Index(it) => match it {},
})
.collect(),
projection: self.result.projection_store.intern(
capture
.place
.projections
.clone()
.into_iter()
.map(|it| match it {
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(it) => ProjectionElem::Field(it),
ProjectionElem::TupleOrClosureField(it) => {
ProjectionElem::TupleOrClosureField(it)
}
ProjectionElem::ConstantIndex { offset, from_end } => {
ProjectionElem::ConstantIndex { offset, from_end }
}
ProjectionElem::Subslice { from, to } => {
ProjectionElem::Subslice { from, to }
}
ProjectionElem::OpaqueCast(it) => {
ProjectionElem::OpaqueCast(it)
}
ProjectionElem::Index(it) => match it {},
})
.collect(),
),
};
match &capture.kind {
CaptureKind::ByRef(bk) => {
@ -1201,7 +1210,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
let Some(values) = elements
.iter()
.map(|it| {
let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else {
let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)?
else {
return Ok(None);
};
current = c;
@ -1254,12 +1264,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
match &self.body.exprs[lhs] {
Expr::Tuple { exprs, is_assignee_expr: _ } => {
for (i, expr) in exprs.iter().enumerate() {
let Some(c) = self.lower_destructing_assignment(
current,
*expr,
rhs.project(ProjectionElem::TupleOrClosureField(i)),
span,
)? else {
let rhs = rhs.project(
ProjectionElem::TupleOrClosureField(i),
&mut self.result.projection_store,
);
let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
else {
return Ok(None);
};
current = c;
@ -1268,8 +1278,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
Expr::Underscore => Ok(Some(current)),
_ => {
let Some((lhs_place, current)) =
self.lower_expr_as_place(current, lhs, false)?
let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
else {
return Ok(None);
};
@ -1286,9 +1295,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
rhs: ExprId,
span: MirSpan,
) -> Result<Option<BasicBlockId>> {
let Some((rhs_op, current)) =
self.lower_expr_to_some_operand(rhs, current)?
else {
let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else {
return Ok(None);
};
if matches!(&self.body.exprs[lhs], Expr::Underscore) {
@ -1303,9 +1310,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.push_assignment(current, temp.clone(), rhs_op.into(), span);
return self.lower_destructing_assignment(current, lhs, temp, span);
}
let Some((lhs_place, current)) =
self.lower_expr_as_place(current, lhs, false)?
else {
let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else {
return Ok(None);
};
self.push_assignment(current, lhs_place, rhs_op.into(), span);
@ -1320,17 +1325,21 @@ impl<'ctx> MirLowerCtx<'ctx> {
placeholder_subst
}
fn push_field_projection(&self, place: &mut Place, expr_id: ExprId) -> Result<()> {
fn push_field_projection(&mut self, place: &mut Place, expr_id: ExprId) -> Result<()> {
if let Expr::Field { expr, name } = &self.body[expr_id] {
if let TyKind::Tuple(..) = self.expr_ty_after_adjustments(*expr).kind(Interner) {
let index = name
.as_tuple_index()
.ok_or(MirLowerError::TypeError("named field on tuple"))?;
*place = place.project(ProjectionElem::TupleOrClosureField(index))
*place = place.project(
ProjectionElem::TupleOrClosureField(index),
&mut self.result.projection_store,
)
} else {
let field =
self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?;
*place = place.project(ProjectionElem::Field(field));
*place =
place.project(ProjectionElem::Field(field), &mut self.result.projection_store);
}
} else {
not_supported!("")
@ -1447,7 +1456,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let name = const_id.name(self.db.upcast());
self.db
.const_eval(const_id.into(), subst, None)
.map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
.map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))?
};
Ok(Operand::Constant(c))
}
@ -1844,7 +1853,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
data.name.display(self.db.upcast()),
data.variants[variant.local_id].name.display(self.db.upcast())
);
Err(MirLowerError::ConstEvalError(name, Box::new(e)))
Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
}
}
}
@ -1992,13 +2001,14 @@ pub fn mir_body_for_closure_query(
FnTrait::FnOnce => vec![],
FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref],
};
ctx.result.walk_places(|p| {
ctx.result.walk_places(|p, store| {
if let Some(it) = upvar_map.get(&p.local) {
let r = it.iter().find(|it| {
if p.projection.len() < it.0.place.projections.len() {
if p.projection.lookup(&store).len() < it.0.place.projections.len() {
return false;
}
for (it, y) in p.projection.iter().zip(it.0.place.projections.iter()) {
for (it, y) in p.projection.lookup(&store).iter().zip(it.0.place.projections.iter())
{
match (it, y) {
(ProjectionElem::Deref, ProjectionElem::Deref) => (),
(ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (),
@ -2016,13 +2026,18 @@ pub fn mir_body_for_closure_query(
p.local = closure_local;
let mut next_projs = closure_projection.clone();
next_projs.push(PlaceElem::TupleOrClosureField(it.1));
let prev_projs = mem::take(&mut p.projection);
let prev_projs = p.projection;
if it.0.kind != CaptureKind::ByValue {
next_projs.push(ProjectionElem::Deref);
}
next_projs
.extend(prev_projs.iter().cloned().skip(it.0.place.projections.len()));
p.projection = next_projs.into();
next_projs.extend(
prev_projs
.lookup(&store)
.iter()
.cloned()
.skip(it.0.place.projections.len()),
);
p.projection = store.intern(next_projs.into());
}
None => err = Some(p.clone()),
}

View file

@ -70,7 +70,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
it.0 = it.0.project(ProjectionElem::Deref);
it.0 = it.0.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some(it))
}
Adjust::Deref(Some(od)) => {
@ -152,7 +152,10 @@ impl MirLowerCtx<'_> {
Operand::Static(s).into(),
expr_id.into(),
);
Ok(Some((temp.project(ProjectionElem::Deref), current)))
Ok(Some((
temp.project(ProjectionElem::Deref, &mut self.result.projection_store),
current,
)))
}
_ => try_rvalue(self),
}
@ -203,7 +206,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
r = r.project(ProjectionElem::Deref);
r = r.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((r, current)))
}
_ => try_rvalue(self),
@ -267,7 +270,8 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
p_base = p_base.project(ProjectionElem::Index(l_index));
p_base = p_base
.project(ProjectionElem::Index(l_index), &mut self.result.projection_store);
Ok(Some((p_base, current)))
}
_ => try_rvalue(self),
@ -308,7 +312,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
result = result.project(ProjectionElem::Deref);
result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current)))
}
@ -363,7 +367,7 @@ impl MirLowerCtx<'_> {
else {
return Ok(None);
};
result = result.project(ProjectionElem::Deref);
result = result.project(ProjectionElem::Deref, &mut self.result.projection_store);
Ok(Some((result, current)))
}
}

View file

@ -81,13 +81,16 @@ impl MirLowerCtx<'_> {
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
cond_place.projection = cond_place
.projection
.iter()
.cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>()
.into();
cond_place.projection = self.result.projection_store.intern(
cond_place
.projection
.lookup(&self.result.projection_store)
.iter()
.cloned()
.chain((0..cnt).map(|_| ProjectionElem::Deref))
.collect::<Vec<_>>()
.into(),
);
Ok(match &self.body.pats[pattern] {
Pat::Missing => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else),
@ -262,20 +265,23 @@ impl MirLowerCtx<'_> {
}
}
for (i, &pat) in prefix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: false,
});
let next_place = (&mut cond_place).project(
ProjectionElem::ConstantIndex { offset: i as u64, from_end: false },
&mut self.result.projection_store,
);
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let Some(slice) = slice {
if mode == MatchingMode::Bind {
if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
let next_place = (&mut cond_place).project(ProjectionElem::Subslice {
from: prefix.len() as u64,
to: suffix.len() as u64,
});
let next_place = (&mut cond_place).project(
ProjectionElem::Subslice {
from: prefix.len() as u64,
to: suffix.len() as u64,
},
&mut self.result.projection_store,
);
(current, current_else) = self.pattern_match_binding(
id,
next_place,
@ -287,10 +293,10 @@ impl MirLowerCtx<'_> {
}
}
for (i, &pat) in suffix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: true,
});
let next_place = (&mut cond_place).project(
ProjectionElem::ConstantIndex { offset: i as u64, from_end: true },
&mut self.result.projection_store,
);
(current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
@ -412,13 +418,11 @@ impl MirLowerCtx<'_> {
mode,
)?
}
Pat::Ref { pat, mutability: _ } => self.pattern_match_inner(
current,
current_else,
cond_place.project(ProjectionElem::Deref),
*pat,
mode,
)?,
Pat::Ref { pat, mutability: _ } => {
let cond_place =
cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
}
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@ -594,7 +598,7 @@ impl MirLowerCtx<'_> {
mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
for (proj, arg) in args {
let cond_place = cond_place.project(proj);
let cond_place = cond_place.project(proj, &mut self.result.projection_store);
(current, current_else) =
self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
}

View file

@ -329,7 +329,7 @@ impl<'a> MirPrettyCtx<'a> {
}
}
}
f(self, p.local, &p.projection);
f(self, p.local, &p.projection.lookup(&self.body.projection_store));
}
fn operand(&mut self, r: &Operand) {

View file

@ -2,55 +2,6 @@ use expect_test::expect;
use super::{check, check_infer, check_no_mismatches, check_types};
#[test]
fn infer_box() {
check_types(
r#"
//- /main.rs crate:main deps:std
fn test() {
let x = box 1;
let t = (x, box x, box &1, box [1]);
t;
} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
//- /std.rs crate:std
#[prelude_import] use prelude::*;
mod prelude {}
mod boxed {
#[lang = "owned_box"]
pub struct Box<T: ?Sized> {
inner: *mut T,
}
}
"#,
);
}
#[test]
fn infer_box_with_allocator() {
check_types(
r#"
//- /main.rs crate:main deps:std
fn test() {
let x = box 1;
let t = (x, box x, box &1, box [1]);
t;
} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
//- /std.rs crate:std
#[prelude_import] use prelude::*;
mod boxed {
#[lang = "owned_box"]
pub struct Box<T: ?Sized, A: Allocator> {
inner: *mut T,
allocator: A,
}
}
"#,
);
}
#[test]
fn infer_adt_self() {
check_types(
@ -2763,8 +2714,8 @@ impl<T> [T] {
}
fn test() {
let vec = <[_]>::into_vec(box [1i32]);
let v: Vec<Box<dyn B>> = <[_]> :: into_vec(box [box Astruct]);
let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32]));
let v: Vec<Box<dyn B>> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)]));
}
trait B{}
@ -2774,20 +2725,20 @@ impl B for Astruct {}
expect![[r#"
604..608 'self': Box<[T], A>
637..669 '{ ... }': Vec<T, A>
683..796 '{ ...t]); }': ()
683..853 '{ ...])); }': ()
693..696 'vec': Vec<i32, Global>
699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
699..726 '<[_]>:...1i32])': Vec<i32, Global>
715..725 'box [1i32]': Box<[i32; 1], Global>
719..725 '[1i32]': [i32; 1]
720..724 '1i32': i32
736..737 'v': Vec<Box<dyn B, Global>, Global>
757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
780..791 'box Astruct': Box<Astruct, Global>
784..791 'Astruct': Astruct
699..745 '<[_]>:...i32]))': Vec<i32, Global>
715..744 '#[rust...1i32])': Box<[i32; 1], Global>
737..743 '[1i32]': [i32; 1]
738..742 '1i32': i32
755..756 'v': Vec<Box<dyn B, Global>, Global>
776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
776..850 '<[_]> ...ct)]))': Vec<Box<dyn B, Global>, Global>
794..849 '#[rust...uct)])': Box<[Box<dyn B, Global>; 1], Global>
816..848 '[#[rus...ruct)]': [Box<dyn B, Global>; 1]
817..847 '#[rust...truct)': Box<Astruct, Global>
839..846 'Astruct': Astruct
"#]],
)
}
@ -3649,3 +3600,30 @@ fn main() {
"#,
);
}
#[test]
fn offset_of() {
check_types(
r#"
fn main() {
builtin#offset_of((,), 0);
// ^^^^^^^^^^^^^^^^^^^^^^^^^ usize
}
"#,
);
}
#[test]
fn builtin_format_args() {
check(
r#"
//- minicore: fmt
fn main() {
let are = "are";
let count = 10;
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
}
"#,
);
}

View file

@ -162,16 +162,16 @@ unsafe impl Allocator for Global {}
#[lang = "owned_box"]
#[fundamental]
pub struct Box<T: ?Sized, A: Allocator = Global>;
pub struct Box<T: ?Sized, A: Allocator = Global>(T);
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
fn send() -> Box<dyn Future<Output = ()> + Send + 'static>{
box async move {}
Box(async move {})
}
fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
box async move {}
Box(async move {})
}
"#,
);
@ -3057,7 +3057,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
fn foo() {
let s = None;
let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
let f: Box<dyn FnOnce(&Option<i32>)> = Box { inner: &mut (|ps| {}) };
f(&s);
}"#,
expect![[r#"
@ -3068,19 +3068,19 @@ fn foo() {
186..197 '*self.inner': T
187..191 'self': &Box<T>
187..197 'self.inner': *mut T
218..308 '{ ...&s); }': ()
218..324 '{ ...&s); }': ()
228..229 's': Option<i32>
232..236 'None': Option<i32>
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
281..294 'box (|ps| {})': Box<impl Fn(&Option<i32>)>
286..293 '|ps| {}': impl Fn(&Option<i32>)
287..289 'ps': &Option<i32>
291..293 '{}': ()
300..301 'f': Box<dyn FnOnce(&Option<i32>)>
300..305 'f(&s)': ()
302..304 '&s': &Option<i32>
303..304 's': Option<i32>
281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<impl Fn(&Option<i32>)>
281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
294..308 '&mut (|ps| {})': &mut impl Fn(&Option<i32>)
300..307 '|ps| {}': impl Fn(&Option<i32>)
301..303 'ps': &Option<i32>
305..307 '{}': ()
316..317 'f': Box<dyn FnOnce(&Option<i32>)>
316..321 'f(&s)': ()
318..320 '&s': &Option<i32>
319..320 's': Option<i32>
"#]],
);
}