提交 bd800181 编写于 作者: L LeSeulArtichaut

Move THIR structure definitions to `rustc_middle`

上级 70cb58ce
......@@ -83,6 +83,7 @@
pub mod lint;
pub mod middle;
pub mod mir;
pub mod thir;
pub mod traits;
pub mod ty;
......
此差异已折叠。
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_middle::mir::*;
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level;
......
//! See docs in build/expr/mod.rs
use crate::build::Builder;
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_middle::mir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
......
......@@ -2,7 +2,7 @@
use crate::build::expr::category::Category;
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
......
......@@ -3,7 +3,7 @@
use crate::build::expr::category::Category;
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
......
......@@ -5,7 +5,7 @@
use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::Place;
......
......@@ -2,7 +2,7 @@
use crate::build::scope::DropKind;
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
......
use crate::thir::*;
use rustc_middle::thir::*;
#[derive(Debug, PartialEq)]
crate enum Category {
......
......@@ -2,7 +2,7 @@
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_ast::InlineAsmOptions;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
......@@ -337,8 +337,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.unit()
}
ExprKind::InlineAsm { template, ref operands, options, line_spans } => {
use crate::thir;
use rustc_middle::mir;
use rustc_middle::{mir, thir};
let operands = operands
.into_iter()
.map(|op| match *op {
......
use crate::build::scope::BreakableTarget;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::thir::*;
use rustc_middle::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
......
......@@ -10,7 +10,6 @@
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
use crate::thir::{self, *};
use rustc_data_structures::{
fx::{FxHashSet, FxIndexMap},
stack::ensure_sufficient_stack,
......@@ -19,6 +18,7 @@
use rustc_index::bit_set::BitSet;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
......@@ -432,7 +432,7 @@ pub(super) fn expr_into_pattern(
..
},
ascription:
thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
} => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
......@@ -687,7 +687,7 @@ pub(super) fn visit_primary_bindings(
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::pattern::Ascription { ref user_ty, user_ty_span, variance: _ },
ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
} => {
// This corresponds to something like
//
......
......@@ -15,8 +15,8 @@
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use crate::thir::{self, *};
use rustc_hir::RangeEnd;
use rustc_middle::thir::{self, *};
use rustc_middle::ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_target::abi::{Integer, Size};
......@@ -152,7 +152,7 @@ fn simplify_match_pair<'pat>(
match *match_pair.pattern.kind {
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
ascription: thir::Ascription { variance, user_ty, user_ty_span },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
candidate.ascriptions.push(Ascription {
......
......@@ -9,11 +9,11 @@
use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
use crate::build::Builder;
use crate::thir::pattern::compare_const_vals;
use crate::thir::*;
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{LangItem, RangeEnd};
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::subst::{GenericArg, Subst};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
......
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::MatchPair;
use crate::build::Builder;
use crate::thir::*;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty;
use smallvec::SmallVec;
use std::convert::TryInto;
......
use crate::build;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use crate::thir::{build_thir, BindingMode, Expr, ExprId, LintLevel, Pat, PatKind, Thir};
use crate::thir::build_thir;
use crate::thir::pattern::pat_from_hir;
use rustc_attr::{self as attr, UnwindAttr};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
......@@ -13,6 +14,7 @@
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
use rustc_span::symbol::{kw, sym};
......@@ -1016,7 +1018,7 @@ fn args_and_body(
Node::Pat(pat) | Node::Binding(pat) => pat,
node => bug!("pattern became {:?}", node),
};
let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat);
let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
let original_source_scope = self.source_scope;
let span = pattern.span;
self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
......
......@@ -82,11 +82,12 @@
*/
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use crate::thir::{Expr, LintLevel};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{Expr, LintLevel};
use rustc_span::{Span, DUMMY_SP};
#[derive(Debug)]
......
use crate::thir::cx::Cx;
use crate::thir::{self, *};
use rustc_hir as hir;
use rustc_middle::middle::region;
use rustc_middle::thir::*;
use rustc_middle::ty;
use rustc_index::vec::Idx;
......@@ -81,7 +81,7 @@ fn mirror_stmts(
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatKind::AscribeUserType {
ascription: thir::pattern::Ascription {
ascription: Ascription {
user_ty: PatTyProj::from_user_type(user_ty),
user_ty_span: ty.span,
variance: ty::Variance::Covariant,
......
use crate::thir::cx::Cx;
use crate::thir::util::UserAnnotatedTyHelpers;
use crate::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
......@@ -8,14 +7,18 @@
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::BorrowKind;
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
};
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, AdtKind, Ty};
use rustc_middle::ty::{self, AdtKind, Ty, UpvarSubsts, UserType};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
impl<'tcx> Cx<'tcx> {
crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
......
......@@ -3,7 +3,7 @@
//! etc., and instead goes through the `Cx` for most of its work.
use crate::thir::util::UserAnnotatedTyHelpers;
use crate::thir::*;
use crate::thir::pattern::pat_from_hir;
use rustc_ast as ast;
use rustc_hir as hir;
......@@ -11,7 +11,9 @@
use rustc_hir::Node;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
pub fn build_thir<'tcx>(
tcx: TyCtxt<'tcx>,
......@@ -79,7 +81,7 @@ fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
Node::Pat(p) | Node::Binding(p) => p,
node => bug!("pattern became {:?}", node),
};
Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
}
}
......
......@@ -4,438 +4,12 @@
//! unit-tested and separated from the Rust source and compiler data
//! structures.
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::newtype_index;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use rustc_target::asm::InlineAsmRegOrRegClass;
use std::ops::Index;
crate mod constant;
crate mod cx;
pub use cx::build_thir;
crate mod pattern;
pub use self::pattern::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
mod util;
pub mod visit;
newtype_index! {
pub struct ArmId {
DEBUG_FORMAT = "a{}"
}
}
newtype_index! {
pub struct ExprId {
DEBUG_FORMAT = "e{}"
}
}
newtype_index! {
pub struct StmtId {
DEBUG_FORMAT = "s{}"
}
}
macro_rules! thir_with_elements {
($($name:ident: $id:ty => $value:ty,)*) => {
pub struct Thir<'tcx> {
$(
$name: IndexVec<$id, $value>,
)*
}
impl<'tcx> Thir<'tcx> {
fn new() -> Thir<'tcx> {
Thir {
$(
$name: IndexVec::new(),
)*
}
}
}
$(
impl<'tcx> Index<$id> for Thir<'tcx> {
type Output = $value;
fn index(&self, index: $id) -> &Self::Output {
&self.$name[index]
}
}
)*
}
}
thir_with_elements! {
arms: ArmId => Arm<'tcx>,
exprs: ExprId => Expr<'tcx>,
stmts: StmtId => Stmt<'tcx>,
}
#[derive(Copy, Clone, Debug)]
pub enum LintLevel {
Inherited,
Explicit(hir::HirId),
}
#[derive(Debug)]
pub struct Block {
pub targeted_by_break: bool,
pub region_scope: region::Scope,
pub opt_destruction_scope: Option<region::Scope>,
pub span: Span,
pub stmts: Box<[StmtId]>,
pub expr: Option<ExprId>,
pub safety_mode: BlockSafety,
}
#[derive(Copy, Clone, Debug)]
pub enum BlockSafety {
Safe,
ExplicitUnsafe(hir::HirId),
PushUnsafe,
PopUnsafe,
}
#[derive(Debug)]
pub struct Stmt<'tcx> {
pub kind: StmtKind<'tcx>,
pub opt_destruction_scope: Option<region::Scope>,
}
#[derive(Debug)]
pub enum StmtKind<'tcx> {
Expr {
/// scope for this statement; may be used as lifetime of temporaries
scope: region::Scope,
/// expression being evaluated in this statement
expr: ExprId,
},
Let {
/// scope for variables bound in this let; covers this and
/// remaining statements in block
remainder_scope: region::Scope,
/// scope for the initialization itself; might be used as
/// lifetime of temporaries
init_scope: region::Scope,
/// `let <PAT> = ...`
///
/// if a type is included, it is added as an ascription pattern
pattern: Pat<'tcx>,
/// let pat: ty = <INIT> ...
initializer: Option<ExprId>,
/// the lint level for this let-statement
lint_level: LintLevel,
},
}
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Expr<'_>, 144);
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
/// into instances of this `Expr` enum. This lowering can be done
/// basically as lazily or as eagerly as desired: every recursive
/// reference to an expression in this enum is an `ExprId`, which
/// may in turn be another instance of this enum (boxed), or else an
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
/// short-lived. They are created by `Thir::to_expr`, analyzed and
/// converted into MIR, and then discarded.
///
/// If you compare `Expr` to the full compiler AST, you will see it is
/// a good bit simpler. In fact, a number of the more straight-forward
/// MIR simplifications are already done in the impl of `Thir`. For
/// example, method calls and overloaded operators are absent: they are
/// expected to be converted into `Expr::Call` instances.
#[derive(Debug)]
pub struct Expr<'tcx> {
/// type of this expression
pub ty: Ty<'tcx>,
/// lifetime of this expression if it should be spilled into a
/// temporary; should be None only if in a constant context
pub temp_lifetime: Option<region::Scope>,
/// span of the expression in the source
pub span: Span,
/// kind of expression
pub kind: ExprKind<'tcx>,
}
#[derive(Debug)]
pub enum ExprKind<'tcx> {
Scope {
region_scope: region::Scope,
lint_level: LintLevel,
value: ExprId,
},
Box {
value: ExprId,
},
If {
cond: ExprId,
then: ExprId,
else_opt: Option<ExprId>,
},
Call {
ty: Ty<'tcx>,
fun: ExprId,
args: Box<[ExprId]>,
/// Whether this is from a call in HIR, rather than from an overloaded
/// operator. `true` for overloaded function call.
from_hir_call: bool,
/// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
fn_span: Span,
},
Deref {
arg: ExprId,
}, // NOT overloaded!
Binary {
op: BinOp,
lhs: ExprId,
rhs: ExprId,
}, // NOT overloaded!
LogicalOp {
op: LogicalOp,
lhs: ExprId,
rhs: ExprId,
}, // NOT overloaded!
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
Unary {
op: UnOp,
arg: ExprId,
}, // NOT overloaded!
Cast {
source: ExprId,
},
Use {
source: ExprId,
}, // Use a lexpr to get a vexpr.
NeverToAny {
source: ExprId,
},
Pointer {
cast: PointerCast,
source: ExprId,
},
Loop {
body: ExprId,
},
Match {
scrutinee: ExprId,
arms: Box<[ArmId]>,
},
Block {
body: Block,
},
Assign {
lhs: ExprId,
rhs: ExprId,
},
AssignOp {
op: BinOp,
lhs: ExprId,
rhs: ExprId,
},
Field {
lhs: ExprId,
name: Field,
},
Index {
lhs: ExprId,
index: ExprId,
},
VarRef {
id: hir::HirId,
},
/// Used to represent upvars mentioned in a closure/generator
UpvarRef {
/// DefId of the closure/generator
closure_def_id: DefId,
/// HirId of the root variable
var_hir_id: hir::HirId,
},
Borrow {
borrow_kind: BorrowKind,
arg: ExprId,
},
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
AddressOf {
mutability: hir::Mutability,
arg: ExprId,
},
Break {
label: region::Scope,
value: Option<ExprId>,
},
Continue {
label: region::Scope,
},
Return {
value: Option<ExprId>,
},
ConstBlock {
value: &'tcx Const<'tcx>,
},
Repeat {
value: ExprId,
count: &'tcx Const<'tcx>,
},
Array {
fields: Box<[ExprId]>,
},
Tuple {
fields: Box<[ExprId]>,
},
Adt {
adt_def: &'tcx AdtDef,
variant_index: VariantIdx,
substs: SubstsRef<'tcx>,
/// Optional user-given substs: for something like `let x =
/// Bar::<T> { ... }`.
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
fields: Box<[FieldExpr]>,
base: Option<FruInfo<'tcx>>,
},
PlaceTypeAscription {
source: ExprId,
/// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
},
ValueTypeAscription {
source: ExprId,
/// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
},
Closure {
closure_id: DefId,
substs: UpvarSubsts<'tcx>,
upvars: Box<[ExprId]>,
movability: Option<hir::Movability>,
fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
},
Literal {
literal: &'tcx Const<'tcx>,
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
/// The `DefId` of the `const` item this literal
/// was produced from, if this is not a user-written
/// literal value.
const_id: Option<DefId>,
},
/// A literal containing the address of a `static`.
///
/// This is only distinguished from `Literal` so that we can register some
/// info for diagnostics.
StaticRef {
literal: &'tcx Const<'tcx>,
def_id: DefId,
},
InlineAsm {
template: &'tcx [InlineAsmTemplatePiece],
operands: Box<[InlineAsmOperand<'tcx>]>,
options: InlineAsmOptions,
line_spans: &'tcx [Span],
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
LlvmInlineAsm {
asm: &'tcx hir::LlvmInlineAsmInner,
outputs: Box<[ExprId]>,
inputs: Box<[ExprId]>,
},
Yield {
value: ExprId,
},
}
#[derive(Debug)]
pub struct FieldExpr {
pub name: Field,
pub expr: ExprId,
}
#[derive(Debug)]
pub struct FruInfo<'tcx> {
pub base: ExprId,
pub field_types: Box<[Ty<'tcx>]>,
}
#[derive(Debug)]
pub struct Arm<'tcx> {
pub pattern: Pat<'tcx>,
pub guard: Option<Guard<'tcx>>,
pub body: ExprId,
pub lint_level: LintLevel,
pub scope: region::Scope,
pub span: Span,
}
#[derive(Debug)]
pub enum Guard<'tcx> {
If(ExprId),
IfLet(Pat<'tcx>, ExprId),
}
#[derive(Copy, Clone, Debug)]
pub enum LogicalOp {
And,
Or,
}
#[derive(Debug)]
pub enum InlineAsmOperand<'tcx> {
In {
reg: InlineAsmRegOrRegClass,
expr: ExprId,
},
Out {
reg: InlineAsmRegOrRegClass,
late: bool,
expr: Option<ExprId>,
},
InOut {
reg: InlineAsmRegOrRegClass,
late: bool,
expr: ExprId,
},
SplitInOut {
reg: InlineAsmRegOrRegClass,
late: bool,
in_expr: ExprId,
out_expr: Option<ExprId>,
},
Const {
value: &'tcx Const<'tcx>,
span: Span,
},
SymFn {
expr: ExprId,
},
SymStatic {
def_id: DefId,
},
}
use super::usefulness::{
compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability,
compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability,
UsefulnessReport,
};
use super::{PatCtxt, PatKind, PatternError};
use super::{PatCtxt, PatternError};
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
......@@ -12,6 +12,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat};
use rustc_middle::thir::PatKind;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
......@@ -344,7 +345,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
/// Checks for common cases of "catchall" patterns that may not be intended as such.
fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
use super::PatKind::*;
use PatKind::*;
match &*pat.kind {
Binding { subpattern: None, .. } => true,
Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
......@@ -514,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>(
if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
&& !is_empty_match
&& witnesses.len() == 1
&& witnesses[0].is_wildcard()
&& is_wildcard(&witnesses[0])
{
err.note(&format!(
"`{}` does not have a fixed maximum value, \
......
......@@ -2,6 +2,7 @@
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::Field;
use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_session::lint;
......@@ -12,7 +13,7 @@
use std::cell::Cell;
use super::{FieldPat, Pat, PatCtxt, PatKind};
use super::PatCtxt;
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts an evaluated constant to a pattern (if possible).
......
......@@ -46,8 +46,7 @@
use self::SliceKind::*;
use super::compare_const_vals;
use super::usefulness::{MatchCheckCtxt, PatCtxt};
use super::{FieldPat, Pat, PatKind, PatRange};
use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
......@@ -55,6 +54,7 @@
use rustc_hir::{HirId, RangeEnd};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::Field;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_session::lint;
......@@ -1245,13 +1245,13 @@ pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>)
// of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
// This is incorrect if the size is not known, since `[_, ..]` captures
// arrays of lengths `>= 1` whereas `[..]` captures any length.
while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
prefix.pop();
}
}
let suffix: Vec<_> = if slice.array_len.is_some() {
// Same as above.
subpatterns.skip_while(Pat::is_wildcard).collect()
subpatterns.skip_while(is_wildcard).collect()
} else {
subpatterns.collect()
};
......
......@@ -11,7 +11,7 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
use rustc_index::vec::Idx;
......@@ -19,16 +19,12 @@
use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
use rustc_middle::mir::UserTypeProjection;
use rustc_middle::mir::{BorrowKind, Field, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_span::{Span, Symbol};
use std::cmp::Ordering;
use std::fmt;
#[derive(Clone, Debug)]
crate enum PatternError {
......@@ -39,317 +35,6 @@
NonConstPath(Span),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BindingMode {
ByValue,
ByRef(BorrowKind),
}
#[derive(Clone, Debug, PartialEq)]
pub struct FieldPat<'tcx> {
pub field: Field,
pub pattern: Pat<'tcx>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Pat<'tcx> {
pub ty: Ty<'tcx>,
pub span: Span,
pub kind: Box<PatKind<'tcx>>,
}
impl<'tcx> Pat<'tcx> {
pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PatTyProj<'tcx> {
pub user_ty: CanonicalUserType<'tcx>,
}
impl<'tcx> PatTyProj<'tcx> {
pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
Self { user_ty: user_annotation }
}
pub(crate) fn user_ty(
self,
annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
inferred_ty: Ty<'tcx>,
span: Span,
) -> UserTypeProjection {
UserTypeProjection {
base: annotations.push(CanonicalUserTypeAnnotation {
span,
user_ty: self.user_ty,
inferred_ty,
}),
projs: Vec::new(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Ascription<'tcx> {
pub user_ty: PatTyProj<'tcx>,
/// Variance to use when relating the type `user_ty` to the **type of the value being
/// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
/// have a type that is some subtype of the ascribed type.
///
/// Note that this variance does not apply for any bindings within subpatterns. The type
/// assigned to those bindings must be exactly equal to the `user_ty` given here.
///
/// The only place where this field is not `Covariant` is when matching constants, where
/// we currently use `Contravariant` -- this is because the constant type just needs to
/// be "comparable" to the type of the input value. So, for example:
///
/// ```text
/// match x { "foo" => .. }
/// ```
///
/// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
/// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
/// of the old type-check for now. See #57280 for details.
pub variance: ty::Variance,
pub user_ty_span: Span,
}
#[derive(Clone, Debug, PartialEq)]
pub enum PatKind<'tcx> {
Wild,
AscribeUserType {
ascription: Ascription<'tcx>,
subpattern: Pat<'tcx>,
},
/// `x`, `ref x`, `x @ P`, etc.
Binding {
mutability: Mutability,
name: Symbol,
mode: BindingMode,
var: hir::HirId,
ty: Ty<'tcx>,
subpattern: Option<Pat<'tcx>>,
/// Is this the leftmost occurrence of the binding, i.e., is `var` the
/// `HirId` of this pattern?
is_primary: bool,
},
/// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
/// multiple variants.
Variant {
adt_def: &'tcx AdtDef,
substs: SubstsRef<'tcx>,
variant_index: VariantIdx,
subpatterns: Vec<FieldPat<'tcx>>,
},
/// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
/// a single variant.
Leaf {
subpatterns: Vec<FieldPat<'tcx>>,
},
/// `box P`, `&P`, `&mut P`, etc.
Deref {
subpattern: Pat<'tcx>,
},
/// One of the following:
/// * `&str`, which will be handled as a string pattern and thus exhaustiveness
/// checking will detect if you use the same string twice in different patterns.
/// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
/// its own value, similar to `&str`, but these values are much simpler.
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
/// `PartialEq` and `Eq`.
Constant {
value: &'tcx ty::Const<'tcx>,
},
Range(PatRange<'tcx>),
/// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
/// e.g., `&[ref xs @ ..]`.
Slice {
prefix: Vec<Pat<'tcx>>,
slice: Option<Pat<'tcx>>,
suffix: Vec<Pat<'tcx>>,
},
/// Fixed match against an array; irrefutable.
Array {
prefix: Vec<Pat<'tcx>>,
slice: Option<Pat<'tcx>>,
suffix: Vec<Pat<'tcx>>,
},
/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
pats: Vec<Pat<'tcx>>,
},
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PatRange<'tcx> {
pub lo: &'tcx ty::Const<'tcx>,
pub hi: &'tcx ty::Const<'tcx>,
pub end: RangeEnd,
}
impl<'tcx> fmt::Display for Pat<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Printing lists is a chore.
let mut first = true;
let mut start_or_continue = |s| {
if first {
first = false;
""
} else {
s
}
};
let mut start_or_comma = || start_or_continue(", ");
match *self.kind {
PatKind::Wild => write!(f, "_"),
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
let is_mut = match mode {
BindingMode::ByValue => mutability == Mutability::Mut,
BindingMode::ByRef(bk) => {
write!(f, "ref ")?;
matches!(bk, BorrowKind::Mut { .. })
}
};
if is_mut {
write!(f, "mut ")?;
}
write!(f, "{}", name)?;
if let Some(ref subpattern) = *subpattern {
write!(f, " @ {}", subpattern)?;
}
Ok(())
}
PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
let variant = match *self.kind {
PatKind::Variant { adt_def, variant_index, .. } => {
Some(&adt_def.variants[variant_index])
}
_ => {
if let ty::Adt(adt, _) = self.ty.kind() {
if !adt.is_enum() {
Some(&adt.variants[VariantIdx::new(0)])
} else {
None
}
} else {
None
}
}
};
if let Some(variant) = variant {
write!(f, "{}", variant.ident)?;
// Only for Adt we can have `S {...}`,
// which we handle separately here.
if variant.ctor_kind == CtorKind::Fictive {
write!(f, " {{ ")?;
let mut printed = 0;
for p in subpatterns {
if let PatKind::Wild = *p.pattern.kind {
continue;
}
let name = variant.fields[p.field.index()].ident;
write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
printed += 1;
}
if printed < variant.fields.len() {
write!(f, "{}..", start_or_comma())?;
}
return write!(f, " }}");
}
}
let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
if num_fields != 0 || variant.is_none() {
write!(f, "(")?;
for i in 0..num_fields {
write!(f, "{}", start_or_comma())?;
// Common case: the field is where we expect it.
if let Some(p) = subpatterns.get(i) {
if p.field.index() == i {
write!(f, "{}", p.pattern)?;
continue;
}
}
// Otherwise, we have to go looking for it.
if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
write!(f, "{}", p.pattern)?;
} else {
write!(f, "_")?;
}
}
write!(f, ")")?;
}
Ok(())
}
PatKind::Deref { ref subpattern } => {
match self.ty.kind() {
ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
ty::Ref(_, _, mutbl) => {
write!(f, "&{}", mutbl.prefix_str())?;
}
_ => bug!("{} is a bad Deref pattern type", self.ty),
}
write!(f, "{}", subpattern)
}
PatKind::Constant { value } => write!(f, "{}", value),
PatKind::Range(PatRange { lo, hi, end }) => {
write!(f, "{}", lo)?;
write!(f, "{}", end)?;
write!(f, "{}", hi)
}
PatKind::Slice { ref prefix, ref slice, ref suffix }
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
write!(f, "[")?;
for p in prefix {
write!(f, "{}{}", start_or_comma(), p)?;
}
if let Some(ref slice) = *slice {
write!(f, "{}", start_or_comma())?;
match *slice.kind {
PatKind::Wild => {}
_ => write!(f, "{}", slice)?,
}
write!(f, "..")?;
}
for p in suffix {
write!(f, "{}{}", start_or_comma(), p)?;
}
write!(f, "]")
}
PatKind::Or { ref pats } => {
for pat in pats {
write!(f, "{}{}", start_or_continue(" | "), pat)?;
}
Ok(())
}
}
}
}
crate struct PatCtxt<'a, 'tcx> {
crate tcx: TyCtxt<'tcx>,
crate param_env: ty::ParamEnv<'tcx>,
......@@ -358,22 +43,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
include_lint_checks: bool,
}
impl<'a, 'tcx> Pat<'tcx> {
crate fn from_hir(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Self {
let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
tcx.sess.delay_span_bug(pat.span, &msg);
}
debug!("Pat::from_hir({:?}) = {:?}", pat, result);
result
}
crate fn pat_from_hir<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Pat<'tcx> {
let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
tcx.sess.delay_span_bug(pat.span, &msg);
}
debug!("pat_from_hir({:?}) = {:?}", pat, result);
result
}
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
......
......@@ -284,7 +284,6 @@
use self::WitnessPreference::*;
use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
use super::{Pat, PatKind};
use super::{PatternFoldable, PatternFolder};
use rustc_data_structures::captures::Captures;
......@@ -294,6 +293,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::thir::{Pat, PatKind};
use rustc_span::Span;
use smallvec::{smallvec, SmallVec};
......@@ -382,31 +382,29 @@ fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
}
}
impl<'tcx> Pat<'tcx> {
pub(super) fn is_wildcard(&self) -> bool {
matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
}
pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool {
matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
}
fn is_or_pat(&self) -> bool {
matches!(*self.kind, PatKind::Or { .. })
}
fn is_or_pat(pat: &Pat<'_>) -> bool {
matches!(*pat.kind, PatKind::Or { .. })
}
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
fn expand_or_pat(&self) -> Vec<&Self> {
fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
if let PatKind::Or { pats } = pat.kind.as_ref() {
for pat in pats {
expand(pat, vec);
}
} else {
vec.push(pat)
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
if let PatKind::Or { pats } = pat.kind.as_ref() {
for pat in pats {
expand(pat, vec);
}
} else {
vec.push(pat)
}
let mut pats = Vec::new();
expand(self, &mut pats);
pats
}
let mut pats = Vec::new();
expand(pat, &mut pats);
pats
}
/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
......@@ -451,7 +449,7 @@ fn iter(&self) -> impl Iterator<Item = &Pat<'tcx>> {
// Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
// or-pattern. Panics if `self` is empty.
fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
self.head().expand_or_pat().into_iter().map(move |pat| {
expand_or_pat(self.head()).into_iter().map(move |pat| {
let mut new_patstack = PatStack::from_pattern(pat);
new_patstack.pats.extend_from_slice(&self.pats[1..]);
new_patstack
......@@ -525,7 +523,7 @@ pub(super) fn column_count(&self) -> Option<usize> {
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
if !row.is_empty() && row.head().is_or_pat() {
if !row.is_empty() && is_or_pat(row.head()) {
for row in row.expand_or_pat() {
self.patterns.push(row);
}
......@@ -760,7 +758,7 @@ fn fill_spans(set: &SubPatSet<'_, '_>, spans: &mut Vec<Span>) {
}
}
SubPatSet::Alt { subpats, pat, alt_count, .. } => {
let expanded = pat.expand_or_pat();
let expanded = expand_or_pat(pat);
for i in 0..*alt_count {
let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
if sub_set.is_empty() {
......@@ -1118,7 +1116,7 @@ fn is_useful<'p, 'tcx>(
let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
// If the first pattern is an or-pattern, expand it.
let ret = if v.head().is_or_pat() {
let ret = if is_or_pat(v.head()) {
debug!("expanding or-pattern");
let v_head = v.head();
let vs: Vec<_> = v.expand_or_pat().collect();
......@@ -1174,7 +1172,7 @@ fn is_useful<'p, 'tcx>(
#[derive(Clone, Copy)]
crate struct MatchArm<'p, 'tcx> {
/// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
crate pat: &'p super::Pat<'tcx>,
crate pat: &'p Pat<'tcx>,
crate hir_id: HirId,
crate has_guard: bool,
}
......@@ -1196,7 +1194,7 @@ fn is_useful<'p, 'tcx>(
crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
/// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
/// exhaustiveness.
crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
crate non_exhaustiveness_witnesses: Vec<Pat<'tcx>>,
}
/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
......@@ -1232,7 +1230,7 @@ fn is_useful<'p, 'tcx>(
})
.collect();
let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty));
let v = PatStack::from_pattern(wild_pattern);
let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
let non_exhaustiveness_witnesses = match usefulness {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册