mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
desugar ? operator
This commit is contained in:
parent
924d277f32
commit
b7b9ae59a0
27 changed files with 517 additions and 191 deletions
|
@ -1,6 +1,6 @@
|
|||
//! This module provides a MIR interpreter, which is used in const eval.
|
||||
|
||||
use std::{borrow::Cow, collections::HashMap, iter};
|
||||
use std::{borrow::Cow, collections::HashMap, iter, sync::Arc};
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{
|
||||
|
@ -24,7 +24,8 @@ use crate::{
|
|||
layout::layout_of_ty,
|
||||
mapping::from_chalk,
|
||||
method_resolution::lookup_impl_method,
|
||||
CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, Ty, TyBuilder, TyExt,
|
||||
CallableDefId, Const, ConstScalar, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
|
||||
TyBuilder, TyExt,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -34,6 +35,7 @@ use super::{
|
|||
|
||||
pub struct Evaluator<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
stack: Vec<u8>,
|
||||
heap: Vec<u8>,
|
||||
crate_id: CrateId,
|
||||
|
@ -217,8 +219,7 @@ pub fn interpret_mir(
|
|||
assert_placeholder_ty_is_unused: bool,
|
||||
) -> Result<Const> {
|
||||
let ty = body.locals[return_slot()].ty.clone();
|
||||
let mut evaluator =
|
||||
Evaluator::new(db, body.owner.module(db.upcast()).krate(), assert_placeholder_ty_is_unused);
|
||||
let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused);
|
||||
let bytes = evaluator.interpret_mir_with_no_arg(&body)?;
|
||||
let memory_map = evaluator.create_memory_map(
|
||||
&bytes,
|
||||
|
@ -231,13 +232,16 @@ pub fn interpret_mir(
|
|||
impl Evaluator<'_> {
|
||||
pub fn new<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
crate_id: CrateId,
|
||||
body: &MirBody,
|
||||
assert_placeholder_ty_is_unused: bool,
|
||||
) -> Evaluator<'a> {
|
||||
let crate_id = body.owner.module(db.upcast()).krate();
|
||||
let trait_env = db.trait_environment_for_body(body.owner);
|
||||
Evaluator {
|
||||
stack: vec![0],
|
||||
heap: vec![0],
|
||||
db,
|
||||
trait_env,
|
||||
crate_id,
|
||||
assert_placeholder_ty_is_unused,
|
||||
stack_depth_limit: 100,
|
||||
|
@ -500,15 +504,9 @@ impl Evaluator<'_> {
|
|||
} else if let Some(x) = self.detect_lang_function(def) {
|
||||
self.exec_lang_item(x, arg_bytes)?
|
||||
} else {
|
||||
let trait_env = {
|
||||
let Some(d) = body.owner.as_generic_def_id() else {
|
||||
not_supported!("trait resolving in non generic def id");
|
||||
};
|
||||
self.db.trait_environment(d)
|
||||
};
|
||||
let (imp, generic_args) = lookup_impl_method(
|
||||
self.db,
|
||||
trait_env,
|
||||
self.trait_env.clone(),
|
||||
def,
|
||||
generic_args.clone(),
|
||||
);
|
||||
|
@ -584,7 +582,7 @@ impl Evaluator<'_> {
|
|||
.to_owned());
|
||||
}
|
||||
Terminator::Unreachable => {
|
||||
return Err(MirEvalError::UndefinedBehavior("unreachable executed"))
|
||||
return Err(MirEvalError::UndefinedBehavior("unreachable executed"));
|
||||
}
|
||||
_ => not_supported!("unknown terminator"),
|
||||
}
|
||||
|
@ -710,8 +708,24 @@ impl Evaluator<'_> {
|
|||
let ty = self.place_ty(p, locals)?;
|
||||
let bytes = self.eval_place(p, locals)?.get(&self)?;
|
||||
let layout = self.layout(&ty)?;
|
||||
let enum_id = 'b: {
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Adt(e, _) => match e.0 {
|
||||
AdtId::EnumId(e) => break 'b e,
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
return Ok(Owned(0u128.to_le_bytes().to_vec()));
|
||||
};
|
||||
match layout.variants {
|
||||
Variants::Single { .. } => Owned(0u128.to_le_bytes().to_vec()),
|
||||
Variants::Single { index } => {
|
||||
let r = self.db.const_eval_discriminant(EnumVariantId {
|
||||
parent: enum_id,
|
||||
local_id: index.0,
|
||||
})?;
|
||||
Owned(r.to_le_bytes().to_vec())
|
||||
}
|
||||
Variants::Multiple { tag, tag_encoding, .. } => {
|
||||
let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else {
|
||||
not_supported!("missing target data layout");
|
||||
|
@ -727,13 +741,6 @@ impl Evaluator<'_> {
|
|||
let tag = &bytes[offset..offset + size];
|
||||
let candidate_discriminant = i128::from_le_bytes(pad16(tag, false))
|
||||
.wrapping_sub(niche_start as i128);
|
||||
let enum_id = match ty.kind(Interner) {
|
||||
TyKind::Adt(e, _) => match e.0 {
|
||||
AdtId::EnumId(e) => e,
|
||||
_ => not_supported!("Non enum with multi variant layout"),
|
||||
},
|
||||
_ => not_supported!("Non adt with multi variant layout"),
|
||||
};
|
||||
let enum_data = self.db.enum_data(enum_id);
|
||||
let result = 'b: {
|
||||
for (local_id, _) in enum_data.variants.iter() {
|
||||
|
@ -790,8 +797,8 @@ impl Evaluator<'_> {
|
|||
Owned(result)
|
||||
}
|
||||
AggregateKind::Adt(x, subst) => {
|
||||
let (size, variant_layout, tag) =
|
||||
self.layout_of_variant(*x, subst.clone(), locals)?;
|
||||
let subst = self.subst_filler(subst, locals);
|
||||
let (size, variant_layout, tag) = self.layout_of_variant(*x, subst, locals)?;
|
||||
Owned(self.make_by_layout(size, &variant_layout, tag, values, locals)?)
|
||||
}
|
||||
},
|
||||
|
@ -1124,12 +1131,13 @@ impl Evaluator<'_> {
|
|||
}
|
||||
|
||||
fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
|
||||
use LangItem::*;
|
||||
let candidate = lang_attr(self.db.upcast(), def)?;
|
||||
// filter normal lang functions out
|
||||
if [LangItem::IntoIterIntoIter, LangItem::IteratorNext].contains(&candidate) {
|
||||
return None;
|
||||
// We want to execute these functions with special logic
|
||||
if [PanicFmt, BeginPanic, SliceLen].contains(&candidate) {
|
||||
return Some(candidate);
|
||||
}
|
||||
Some(candidate)
|
||||
None
|
||||
}
|
||||
|
||||
fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result<MemoryMap> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue