1
Fork 0

Rollup merge of #67730 - Centril:typeck-pat-cleanup, r=estebank

Cleanup pattern type checking, fix diagnostics bugs (+ improvements)

r? @estebank
This commit is contained in:
Mazdak Farrokhzad 2019-12-31 19:19:36 +01:00 committed by GitHub
commit 50fb8480db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 418 additions and 244 deletions

View file

@ -581,10 +581,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
) { ) {
match cause.code { match cause.code {
ObligationCauseCode::MatchExpressionArmPattern { span, ty } => { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
let ty = self.resolve_vars_if_possible(&root_ty);
if ty.is_suggestable() { if ty.is_suggestable() {
// don't show type `_` // don't show type `_`
err.span_label(span, format!("this match expression has type `{}`", ty)); err.span_label(span, format!("this expression has type `{}`", ty));
} }
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found { if let Some(ty::error::ExpectedFound { found, .. }) = exp_found {
if ty.is_box() && ty.boxed_ty() == found { if ty.is_box() && ty.boxed_ty() == found {
@ -599,11 +600,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
} }
} }
ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
err.span_label(span, "expected due to this");
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
source, source,
ref prior_arms, ref prior_arms,
last_ty, last_ty,
discrim_hir_id, scrut_hir_id,
.. ..
}) => match source { }) => match source {
hir::MatchSource::IfLetDesugar { .. } => { hir::MatchSource::IfLetDesugar { .. } => {
@ -612,16 +616,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
hir::MatchSource::TryDesugar => { hir::MatchSource::TryDesugar => {
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
let discrim_expr = self.tcx.hir().expect_expr(discrim_hir_id); let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.kind { let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
let arg_expr = args.first().expect("try desugaring call w/out arg"); let arg_expr = args.first().expect("try desugaring call w/out arg");
self.in_progress_tables self.in_progress_tables
.and_then(|tables| tables.borrow().expr_ty_opt(arg_expr)) .and_then(|tables| tables.borrow().expr_ty_opt(arg_expr))
} else { } else {
bug!("try desugaring w/out call expr as discriminant"); bug!("try desugaring w/out call expr as scrutinee");
}; };
match discrim_ty { match scrut_ty {
Some(ty) if expected == ty => { Some(ty) if expected == ty => {
let source_map = self.tcx.sess.source_map(); let source_map = self.tcx.sess.source_map();
err.span_suggestion( err.span_suggestion(

View file

@ -2580,7 +2580,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match *cause_code { match *cause_code {
ObligationCauseCode::ExprAssignable ObligationCauseCode::ExprAssignable
| ObligationCauseCode::MatchExpressionArm { .. } | ObligationCauseCode::MatchExpressionArm { .. }
| ObligationCauseCode::MatchExpressionArmPattern { .. } | ObligationCauseCode::Pattern { .. }
| ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::IfExpression { .. }
| ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::IfExpressionWithNoElse
| ObligationCauseCode::MainFunctionType | ObligationCauseCode::MainFunctionType

View file

@ -249,10 +249,14 @@ pub enum ObligationCauseCode<'tcx> {
/// Computing common supertype in the arms of a match expression /// Computing common supertype in the arms of a match expression
MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>), MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
/// Computing common supertype in the pattern guard for the arms of a match expression /// Type error arising from type checking a pattern against an expected type.
MatchExpressionArmPattern { Pattern {
span: Span, /// The span of the scrutinee or type expression which caused the `root_ty` type.
ty: Ty<'tcx>, span: Option<Span>,
/// The root expected type induced by a scrutinee or type expression.
root_ty: Ty<'tcx>,
/// Whether the `Span` came from an expression or a type expression.
origin_expr: bool,
}, },
/// Constants in patterns must have `Structural` type. /// Constants in patterns must have `Structural` type.
@ -311,7 +315,7 @@ pub struct MatchExpressionArmCause<'tcx> {
pub source: hir::MatchSource, pub source: hir::MatchSource,
pub prior_arms: Vec<Span>, pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>, pub last_ty: Ty<'tcx>,
pub discrim_hir_id: hir::HirId, pub scrut_hir_id: hir::HirId,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -511,18 +511,18 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
source, source,
ref prior_arms, ref prior_arms,
last_ty, last_ty,
discrim_hir_id, scrut_hir_id,
}) => tcx.lift(&last_ty).map(|last_ty| { }) => tcx.lift(&last_ty).map(|last_ty| {
super::MatchExpressionArm(box super::MatchExpressionArmCause { super::MatchExpressionArm(box super::MatchExpressionArmCause {
arm_span, arm_span,
source, source,
prior_arms: prior_arms.clone(), prior_arms: prior_arms.clone(),
last_ty, last_ty,
discrim_hir_id, scrut_hir_id,
}) })
}), }),
super::MatchExpressionArmPattern { span, ty } => { super::Pattern { span, root_ty, origin_expr } => {
tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr })
} }
super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }))

View file

@ -11,7 +11,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_match( pub fn check_match(
&self, &self,
expr: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>,
discrim: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>,
arms: &'tcx [hir::Arm<'tcx>], arms: &'tcx [hir::Arm<'tcx>],
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
match_src: hir::MatchSource, match_src: hir::MatchSource,
@ -27,7 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
// Type check the descriminant and get its type. // Type check the descriminant and get its type.
let discrim_ty = if force_scrutinee_bool { let scrut_ty = if force_scrutinee_bool {
// Here we want to ensure: // Here we want to ensure:
// //
// 1. That default match bindings are *not* accepted in the condition of an // 1. That default match bindings are *not* accepted in the condition of an
@ -36,9 +36,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`. // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`.
// //
// FIXME(60707): Consider removing hack with principled solution. // FIXME(60707): Consider removing hack with principled solution.
self.check_expr_has_type_or_error(discrim, self.tcx.types.bool, |_| {}) self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {})
} else { } else {
self.demand_discriminant_type(arms, discrim) self.demand_scrutinee_type(arms, scrut)
}; };
// If there are no arms, that is a diverging match; a special case. // If there are no arms, that is a diverging match; a special case.
@ -51,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Otherwise, we have to union together the types that the // Otherwise, we have to union together the types that the
// arms produce and so forth. // arms produce and so forth.
let discrim_diverges = self.diverges.get(); let scrut_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe); self.diverges.set(Diverges::Maybe);
// rust-lang/rust#55810: Typecheck patterns first (via eager // rust-lang/rust#55810: Typecheck patterns first (via eager
@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.map(|arm| { .map(|arm| {
let mut all_pats_diverge = Diverges::WarnedAlways; let mut all_pats_diverge = Diverges::WarnedAlways;
self.diverges.set(Diverges::Maybe); self.diverges.set(Diverges::Maybe);
self.check_pat_top(&arm.pat, discrim_ty, Some(discrim.span)); self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true);
all_pats_diverge &= self.diverges.get(); all_pats_diverge &= self.diverges.get();
// As discussed with @eddyb, this is for disabling unreachable_code // As discussed with @eddyb, this is for disabling unreachable_code
@ -157,7 +157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
source: match_src, source: match_src,
prior_arms: other_arms.clone(), prior_arms: other_arms.clone(),
last_ty: prior_arm_ty.unwrap(), last_ty: prior_arm_ty.unwrap(),
discrim_hir_id: discrim.hir_id, scrut_hir_id: scrut.hir_id,
}), }),
), ),
}; };
@ -186,8 +186,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
} }
// We won't diverge unless the discriminant or all arms diverge. // We won't diverge unless the scrutinee or all arms diverge.
self.diverges.set(discrim_diverges | all_arms_diverge); self.diverges.set(scrut_diverges | all_arms_diverge);
coercion.complete(self) coercion.complete(self)
} }
@ -388,14 +388,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
} }
fn demand_discriminant_type( fn demand_scrutinee_type(
&self, &self,
arms: &'tcx [hir::Arm<'tcx>], arms: &'tcx [hir::Arm<'tcx>],
discrim: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
// Not entirely obvious: if matches may create ref bindings, we want to // Not entirely obvious: if matches may create ref bindings, we want to
// use the *precise* type of the discriminant, *not* some supertype, as // use the *precise* type of the scrutinee, *not* some supertype, as
// the "discriminant type" (issue #23116). // the "scrutinee type" (issue #23116).
// //
// arielb1 [writes here in this comment thread][c] that there // arielb1 [writes here in this comment thread][c] that there
// is certainly *some* potential danger, e.g., for an example // is certainly *some* potential danger, e.g., for an example
@ -454,17 +454,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}); });
if let Some(m) = contains_ref_bindings { if let Some(m) = contains_ref_bindings {
self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)) self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m))
} else { } else {
// ...but otherwise we want to use any supertype of the // ...but otherwise we want to use any supertype of the
// discriminant. This is sort of a workaround, see note (*) in // scrutinee. This is sort of a workaround, see note (*) in
// `check_pat` for some details. // `check_pat` for some details.
let discrim_ty = self.next_ty_var(TypeVariableOrigin { let scrut_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference, kind: TypeVariableOriginKind::TypeInference,
span: discrim.span, span: scrut.span,
}); });
self.check_expr_has_type_or_error(discrim, discrim_ty, |_| {}); self.check_expr_has_type_or_error(scrut, scrut_ty, |_| {});
discrim_ty scrut_ty
} }
} }
} }

View file

@ -1,6 +1,6 @@
use crate::check::FnCtxt; use crate::check::FnCtxt;
use rustc::infer::InferOk; use rustc::infer::InferOk;
use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::traits::{self, ObligationCause};
use errors::{Applicability, DiagnosticBuilder}; use errors::{Applicability, DiagnosticBuilder};
use rustc::hir::{self, is_range_literal, print, Node}; use rustc::hir::{self, is_range_literal, print, Node};
@ -79,35 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
pub fn demand_eqtype_pat_diag(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
match_expr_span: Option<Span>,
) -> Option<DiagnosticBuilder<'tcx>> {
let cause = if let Some(span) = match_expr_span {
self.cause(
cause_span,
ObligationCauseCode::MatchExpressionArmPattern { span, ty: expected },
)
} else {
self.misc(cause_span)
};
self.demand_eqtype_with_origin(&cause, expected, actual)
}
pub fn demand_eqtype_pat(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
match_expr_span: Option<Span>,
) {
self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
.map(|mut err| err.emit());
}
pub fn demand_coerce( pub fn demand_coerce(
&self, &self,
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,

View file

@ -1268,13 +1268,17 @@ fn check_fn<'a, 'tcx>(
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
*fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
let tcx = fcx.tcx;
let sess = tcx.sess;
let hir = tcx.hir();
let declared_ret_ty = fn_sig.output(); let declared_ret_ty = fn_sig.output();
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
let revealed_ret_ty = let revealed_ret_ty =
fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
fn_sig = fcx.tcx.mk_fn_sig( fn_sig = tcx.mk_fn_sig(
fn_sig.inputs().iter().cloned(), fn_sig.inputs().iter().cloned(),
revealed_ret_ty, revealed_ret_ty,
fn_sig.c_variadic, fn_sig.c_variadic,
@ -1284,7 +1288,7 @@ fn check_fn<'a, 'tcx>(
let span = body.value.span; let span = body.value.span;
fn_maybe_err(fcx.tcx, span, fn_sig.abi); fn_maybe_err(tcx, span, fn_sig.abi);
if body.generator_kind.is_some() && can_be_generator.is_some() { if body.generator_kind.is_some() && can_be_generator.is_some() {
let yield_ty = fcx let yield_ty = fcx
@ -1293,37 +1297,39 @@ fn check_fn<'a, 'tcx>(
fcx.yield_ty = Some(yield_ty); fcx.yield_ty = Some(yield_ty);
} }
let outer_def_id = fcx.tcx.closure_base_def_id(fcx.tcx.hir().local_def_id(fn_id)); let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id));
let outer_hir_id = fcx.tcx.hir().as_local_hir_id(outer_def_id).unwrap(); let outer_hir_id = hir.as_local_hir_id(outer_def_id).unwrap();
GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body); GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body);
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
// (as it's created inside the body itself, not passed in from outside). // (as it's created inside the body itself, not passed in from outside).
let maybe_va_list = if fn_sig.c_variadic { let maybe_va_list = if fn_sig.c_variadic {
let va_list_did = fcx.tcx.require_lang_item( let va_list_did = tcx.require_lang_item(
lang_items::VaListTypeLangItem, lang_items::VaListTypeLangItem,
Some(body.params.last().unwrap().span), Some(body.params.last().unwrap().span),
); );
let region = fcx.tcx.mk_region(ty::ReScope(region::Scope { let region = tcx.mk_region(ty::ReScope(region::Scope {
id: body.value.hir_id.local_id, id: body.value.hir_id.local_id,
data: region::ScopeData::CallSite, data: region::ScopeData::CallSite,
})); }));
Some(fcx.tcx.type_of(va_list_did).subst(fcx.tcx, &[region.into()])) Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()]))
} else { } else {
None None
}; };
// Add formal parameters. // Add formal parameters.
for (param_ty, param) in fn_sig.inputs().iter().copied().chain(maybe_va_list).zip(body.params) { let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
let inputs_fn = fn_sig.inputs().iter().copied();
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
// Check the pattern. // Check the pattern.
fcx.check_pat_top(&param.pat, param_ty, None); fcx.check_pat_top(&param.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false);
// Check that argument is Sized. // Check that argument is Sized.
// The check for a non-trivial pattern is a hack to avoid duplicate warnings // The check for a non-trivial pattern is a hack to avoid duplicate warnings
// for simple cases like `fn foo(x: Trait)`, // for simple cases like `fn foo(x: Trait)`,
// where we would error once on the parameter as a whole, and once on the binding `x`. // where we would error once on the parameter as a whole, and once on the binding `x`.
if param.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals {
fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType); fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType);
} }
@ -1384,11 +1390,11 @@ fn check_fn<'a, 'tcx>(
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
// Check that the main return type implements the termination trait. // Check that the main return type implements the termination trait.
if let Some(term_id) = fcx.tcx.lang_items().termination() { if let Some(term_id) = tcx.lang_items().termination() {
if let Some((def_id, EntryFnType::Main)) = fcx.tcx.entry_fn(LOCAL_CRATE) { if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
let main_id = fcx.tcx.hir().as_local_hir_id(def_id).unwrap(); let main_id = hir.as_local_hir_id(def_id).unwrap();
if main_id == fn_id { if main_id == fn_id {
let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]); let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
let trait_ref = ty::TraitRef::new(term_id, substs); let trait_ref = ty::TraitRef::new(term_id, substs);
let return_ty_span = decl.output.span(); let return_ty_span = decl.output.span();
let cause = traits::ObligationCause::new( let cause = traits::ObligationCause::new(
@ -1407,15 +1413,15 @@ fn check_fn<'a, 'tcx>(
} }
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() { if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
if panic_impl_did == fcx.tcx.hir().local_def_id(fn_id) { if panic_impl_did == hir.local_def_id(fn_id) {
if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() { if let Some(panic_info_did) = tcx.lang_items().panic_info() {
if declared_ret_ty.kind != ty::Never { if declared_ret_ty.kind != ty::Never {
fcx.tcx.sess.span_err(decl.output.span(), "return type should be `!`"); sess.span_err(decl.output.span(), "return type should be `!`");
} }
let inputs = fn_sig.inputs(); let inputs = fn_sig.inputs();
let span = fcx.tcx.hir().span(fn_id); let span = hir.span(fn_id);
if inputs.len() == 1 { if inputs.len() == 1 {
let arg_is_panic_info = match inputs[0].kind { let arg_is_panic_info = match inputs[0].kind {
ty::Ref(region, ty, mutbl) => match ty.kind { ty::Ref(region, ty, mutbl) => match ty.kind {
@ -1430,38 +1436,36 @@ fn check_fn<'a, 'tcx>(
}; };
if !arg_is_panic_info { if !arg_is_panic_info {
fcx.tcx sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
.sess
.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
} }
if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { if let Node::Item(item) = hir.get(fn_id) {
if let ItemKind::Fn(_, ref generics, _) = item.kind { if let ItemKind::Fn(_, ref generics, _) = item.kind {
if !generics.params.is_empty() { if !generics.params.is_empty() {
fcx.tcx.sess.span_err(span, "should have no type parameters"); sess.span_err(span, "should have no type parameters");
} }
} }
} }
} else { } else {
let span = fcx.tcx.sess.source_map().def_span(span); let span = sess.source_map().def_span(span);
fcx.tcx.sess.span_err(span, "function should have one argument"); sess.span_err(span, "function should have one argument");
} }
} else { } else {
fcx.tcx.sess.err("language item required, but not found: `panic_info`"); sess.err("language item required, but not found: `panic_info`");
} }
} }
} }
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() { if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
if alloc_error_handler_did == fcx.tcx.hir().local_def_id(fn_id) { if alloc_error_handler_did == hir.local_def_id(fn_id) {
if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() { if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
if declared_ret_ty.kind != ty::Never { if declared_ret_ty.kind != ty::Never {
fcx.tcx.sess.span_err(decl.output.span(), "return type should be `!`"); sess.span_err(decl.output.span(), "return type should be `!`");
} }
let inputs = fn_sig.inputs(); let inputs = fn_sig.inputs();
let span = fcx.tcx.hir().span(fn_id); let span = hir.span(fn_id);
if inputs.len() == 1 { if inputs.len() == 1 {
let arg_is_alloc_layout = match inputs[0].kind { let arg_is_alloc_layout = match inputs[0].kind {
ty::Adt(ref adt, _) => adt.did == alloc_layout_did, ty::Adt(ref adt, _) => adt.did == alloc_layout_did,
@ -1469,13 +1473,13 @@ fn check_fn<'a, 'tcx>(
}; };
if !arg_is_alloc_layout { if !arg_is_alloc_layout {
fcx.tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
} }
if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { if let Node::Item(item) = hir.get(fn_id) {
if let ItemKind::Fn(_, ref generics, _) = item.kind { if let ItemKind::Fn(_, ref generics, _) = item.kind {
if !generics.params.is_empty() { if !generics.params.is_empty() {
fcx.tcx.sess.span_err( sess.span_err(
span, span,
"`#[alloc_error_handler]` function should have no type \ "`#[alloc_error_handler]` function should have no type \
parameters", parameters",
@ -1484,11 +1488,11 @@ fn check_fn<'a, 'tcx>(
} }
} }
} else { } else {
let span = fcx.tcx.sess.source_map().def_span(span); let span = sess.source_map().def_span(span);
fcx.tcx.sess.span_err(span, "function should have one argument"); sess.span_err(span, "function should have one argument");
} }
} else { } else {
fcx.tcx.sess.err("language item required, but not found: `alloc_layout`"); sess.err("language item required, but not found: `alloc_layout`");
} }
} }
} }
@ -4304,18 +4308,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
/// Type check a `let` statement.
pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
let t = self.local_ty(local.span, local.hir_id).decl_ty; // Determine and write the type which we'll check the pattern against.
self.write_ty(local.hir_id, t); let ty = self.local_ty(local.span, local.hir_id).decl_ty;
self.write_ty(local.hir_id, ty);
// Type check the initializer.
if let Some(ref init) = local.init { if let Some(ref init) = local.init {
let init_ty = self.check_decl_initializer(local, &init); let init_ty = self.check_decl_initializer(local, &init);
self.overwrite_local_ty_if_err(local, t, init_ty); self.overwrite_local_ty_if_err(local, ty, init_ty);
} }
self.check_pat_top(&local.pat, t, None); // Does the expected pattern type originate from an expression and what is the span?
let (origin_expr, ty_span) = match (local.ty, local.init) {
(Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
(_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
_ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
};
// Type check the pattern. Override if necessary to avoid knock-on errors.
self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
let pat_ty = self.node_ty(local.pat.hir_id); let pat_ty = self.node_ty(local.pat.hir_id);
self.overwrite_local_ty_if_err(local, t, pat_ty); self.overwrite_local_ty_if_err(local, ty, pat_ty);
} }
fn overwrite_local_ty_if_err( fn overwrite_local_ty_if_err(
@ -4325,7 +4340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>, ty: Ty<'tcx>,
) { ) {
if ty.references_error() { if ty.references_error() {
// Override the types everywhere with `types.err` to avoid knock down errors. // Override the types everywhere with `types.err` to avoid knock on errors.
self.write_ty(local.hir_id, ty); self.write_ty(local.hir_id, ty);
self.write_ty(local.pat.hir_id, ty); self.write_ty(local.pat.hir_id, ty);
let local_ty = LocalTy { decl_ty, revealed_ty: ty }; let local_ty = LocalTy { decl_ty, revealed_ty: ty };

View file

@ -6,6 +6,7 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::hir::{self, HirId, Pat, PatKind}; use rustc::hir::{self, HirId, Pat, PatKind};
use rustc::infer; use rustc::infer;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc::traits::Pattern;
use rustc::ty::subst::GenericArg; use rustc::ty::subst::GenericArg;
use rustc::ty::{self, BindingMode, Ty, TypeFoldable}; use rustc::ty::{self, BindingMode, Ty, TypeFoldable};
use syntax::ast; use syntax::ast;
@ -29,39 +30,97 @@ pointers. If you encounter this error you should try to avoid dereferencing the
You can read more about trait objects in the Trait Objects section of the Reference: \ You can read more about trait objects in the Trait Objects section of the Reference: \
https://doc.rust-lang.org/reference/types.html#trait-objects"; https://doc.rust-lang.org/reference/types.html#trait-objects";
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Information about the expected type at the top level of type checking a pattern.
pub fn check_pat_top( ///
&self, /// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic!
pat: &'tcx Pat<'tcx>, #[derive(Copy, Clone)]
expected: Ty<'tcx>, struct TopInfo<'tcx> {
discrim_span: Option<Span>, /// The `expected` type at the top level of type checking a pattern.
) { expected: Ty<'tcx>,
let def_bm = BindingMode::BindByValue(hir::Mutability::Not); /// Was the origin of the `span` from a scrutinee expression?
self.check_pat(pat, expected, def_bm, discrim_span); ///
} /// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter.
origin_expr: bool,
/// `discrim_span` argument having a `Span` indicates that this pattern is part of a match /// The span giving rise to the `expected` type, if one could be provided.
/// expression arm guard, and it points to the match discriminant to add context in type errors. ///
/// In the following example, `discrim_span` corresponds to the `a + b` expression: /// If `origin_expr` is `true`, then this is the span of the scrutinee as in:
///
/// - `match scrutinee { ... }`
/// - `let _ = scrutinee;`
///
/// This is used to point to add context in type errors.
/// In the following example, `span` corresponds to the `a + b` expression:
/// ///
/// ```text /// ```text
/// error[E0308]: mismatched types /// error[E0308]: mismatched types
/// --> src/main.rs:5:9 /// --> src/main.rs:L:C
/// | /// |
/// 4 | let temp: usize = match a + b { /// L | let temp: usize = match a + b {
/// | ----- this expression has type `usize` /// | ----- this expression has type `usize`
/// 5 | Ok(num) => num, /// L | Ok(num) => num,
/// | ^^^^^^^ expected `usize`, found enum `std::result::Result` /// | ^^^^^^^ expected `usize`, found enum `std::result::Result`
/// | /// |
/// = note: expected type `usize` /// = note: expected type `usize`
/// found type `std::result::Result<_, _>` /// found type `std::result::Result<_, _>`
/// ``` /// ```
span: Option<Span>,
}
impl<'tcx> FnCtxt<'_, 'tcx> {
fn demand_eqtype_pat_diag(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
) -> Option<DiagnosticBuilder<'tcx>> {
let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
let cause = self.cause(cause_span, code);
self.demand_eqtype_with_origin(&cause, expected, actual)
}
fn demand_eqtype_pat(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
) {
self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map(|mut err| err.emit());
}
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Type check the given top level pattern against the `expected` type.
///
/// If a `Some(span)` is provided and `origin_expr` holds,
/// then the `span` represents the scrutinee's span.
/// The scrutinee is found in e.g. `match scrutinee { ... }` and `let pat = scrutinee;`.
///
/// Otherwise, `Some(span)` represents the span of a type expression
/// which originated the `expected` type.
pub fn check_pat_top(
&self,
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
span: Option<Span>,
origin_expr: bool,
) {
let def_bm = BindingMode::BindByValue(hir::Mutability::Not);
self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span });
}
/// Type check the given `pat` against the `expected` type
/// with the provided `def_bm` (default binding mode).
///
/// Outside of this module, `check_pat_top` should always be used.
/// Conversely, inside this module, `check_pat_top` should never be used.
fn check_pat( fn check_pat(
&self, &self,
pat: &'tcx Pat<'tcx>, pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) { ) {
debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
@ -72,60 +131,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res)); let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res));
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp); let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp);
let ty = match &pat.kind { let ty = match pat.kind {
PatKind::Wild => expected, PatKind::Wild => expected,
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, discrim_span), PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(begin, end, _) => { PatKind::Range(begin, end, _) => {
match self.check_pat_range(pat.span, begin, end, expected, discrim_span) { match self.check_pat_range(pat.span, begin, end, expected, ti) {
None => return, None => return,
Some(ty) => ty, Some(ty) => ty,
} }
} }
PatKind::Binding(ba, var_id, _, sub) => { PatKind::Binding(ba, var_id, _, sub) => {
let sub = sub.as_deref(); self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti)
self.check_pat_ident(pat, *ba, *var_id, sub, expected, def_bm, discrim_span)
} }
PatKind::TupleStruct(qpath, subpats, ddpos) => self.check_pat_tuple_struct( PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
pat, self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
qpath, }
subpats, PatKind::Path(ref qpath) => {
*ddpos,
expected,
def_bm,
discrim_span,
),
PatKind::Path(qpath) => {
self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected)
} }
PatKind::Struct(qpath, fields, etc) => { PatKind::Struct(ref qpath, fields, etc) => {
self.check_pat_struct(pat, qpath, fields, *etc, expected, def_bm, discrim_span) self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
} }
PatKind::Or(pats) => { PatKind::Or(pats) => {
for pat in *pats { for pat in pats {
self.check_pat(pat, expected, def_bm, discrim_span); self.check_pat(pat, expected, def_bm, ti);
} }
expected expected
} }
PatKind::Tuple(elements, ddpos) => { PatKind::Tuple(elements, ddpos) => {
self.check_pat_tuple(pat.span, *elements, *ddpos, expected, def_bm, discrim_span) self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti)
}
PatKind::Box(inner) => {
self.check_pat_box(pat.span, inner, expected, def_bm, discrim_span)
} }
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti),
PatKind::Ref(inner, mutbl) => { PatKind::Ref(inner, mutbl) => {
self.check_pat_ref(pat, inner, *mutbl, expected, def_bm, discrim_span) self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti)
} }
PatKind::Slice(before, slice, after) => { PatKind::Slice(before, slice, after) => {
let slice = slice.as_deref(); self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti)
self.check_pat_slice(
pat.span,
*before,
slice,
*after,
expected,
def_bm,
discrim_span,
)
} }
}; };
@ -302,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span, span: Span,
lt: &hir::Expr<'tcx>, lt: &hir::Expr<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
// We've already computed the type above (when checking for a non-ref pat), // We've already computed the type above (when checking for a non-ref pat),
// so avoid computing it again. // so avoid computing it again.
@ -336,7 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// then that's equivalent to there existing a LUB. // then that's equivalent to there existing a LUB.
if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) { if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) {
err.emit_unless( err.emit_unless(
discrim_span ti.span
.filter(|&s| { .filter(|&s| {
// In the case of `if`- and `while`-expressions we've already checked // In the case of `if`- and `while`-expressions we've already checked
// that `scrutinee: bool`. We know that the pattern is `true`, // that `scrutinee: bool`. We know that the pattern is `true`,
@ -356,7 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lhs: &'tcx hir::Expr<'tcx>, lhs: &'tcx hir::Expr<'tcx>,
rhs: &'tcx hir::Expr<'tcx>, rhs: &'tcx hir::Expr<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Option<Ty<'tcx>> { ) -> Option<Ty<'tcx>> {
let lhs_ty = self.check_expr(lhs); let lhs_ty = self.check_expr(lhs);
let rhs_ty = self.check_expr(rhs); let rhs_ty = self.check_expr(rhs);
@ -377,7 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Subtyping doesn't matter here, as the value is some kind of scalar. // Subtyping doesn't matter here, as the value is some kind of scalar.
let demand_eqtype = |x_span, y_span, x_ty, y_ty| { let demand_eqtype = |x_span, y_span, x_ty, y_ty| {
self.demand_eqtype_pat_diag(x_span, expected, x_ty, discrim_span).map(|mut err| { self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| {
self.endpoint_has_type(&mut err, y_span, y_ty); self.endpoint_has_type(&mut err, y_span, y_ty);
err.emit(); err.emit();
}); });
@ -451,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sub: Option<&'tcx Pat<'tcx>>, sub: Option<&'tcx Pat<'tcx>>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
// Determine the binding mode... // Determine the binding mode...
let bm = match ba { let bm = match ba {
@ -481,17 +522,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected expected
} }
}; };
self.demand_eqtype_pat(pat.span, eq_ty, local_ty, discrim_span); self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti);
// If there are multiple arms, make sure they all agree on // If there are multiple arms, make sure they all agree on
// what the type of the binding `x` ought to be. // what the type of the binding `x` ought to be.
if var_id != pat.hir_id { if var_id != pat.hir_id {
let vt = self.local_ty(pat.span, var_id).decl_ty; let vt = self.local_ty(pat.span, var_id).decl_ty;
self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); self.demand_eqtype_pat(pat.span, vt, local_ty, ti);
} }
if let Some(p) = sub { if let Some(p) = sub {
self.check_pat(&p, expected, def_bm, discrim_span); self.check_pat(&p, expected, def_bm, ti);
} }
local_ty local_ty
@ -570,7 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
etc: bool, etc: bool,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
// Resolve the path and check the definition for errors. // Resolve the path and check the definition for errors.
let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id)
@ -578,16 +619,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant_ty variant_ty
} else { } else {
for field in fields { for field in fields {
self.check_pat(&field.pat, self.tcx.types.err, def_bm, discrim_span); self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti);
} }
return self.tcx.types.err; return self.tcx.types.err;
}; };
// Type-check the path. // Type-check the path.
self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); self.demand_eqtype_pat(pat.span, expected, pat_ty, ti);
// Type-check subpatterns. // Type-check subpatterns.
if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) if self
.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm, ti)
{ {
pat_ty pat_ty
} else { } else {
@ -638,12 +680,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ddpos: Option<usize>, ddpos: Option<usize>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
match_arm_pat_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let on_error = || { let on_error = || {
for pat in subpats { for pat in subpats {
self.check_pat(&pat, tcx.types.err, def_bm, match_arm_pat_span); self.check_pat(&pat, tcx.types.err, def_bm, ti);
} }
}; };
let report_unexpected_res = |res: Res| { let report_unexpected_res = |res: Res| {
@ -704,7 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
// Type-check the tuple struct pattern against the expected type. // Type-check the tuple struct pattern against the expected type.
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span); let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti);
let had_err = diag.is_some(); let had_err = diag.is_some();
diag.map(|mut err| err.emit()); diag.map(|mut err| err.emit());
@ -718,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
self.check_pat(&subpat, field_ty, def_bm, match_arm_pat_span); self.check_pat(&subpat, field_ty, def_bm, ti);
self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span);
} }
@ -822,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ddpos: Option<usize>, ddpos: Option<usize>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let mut expected_len = elements.len(); let mut expected_len = elements.len();
@ -849,12 +891,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// further errors being emitted when using the bindings. #50333 // further errors being emitted when using the bindings. #50333
let element_tys_iter = (0..max_len).map(|_| tcx.types.err); let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat(elem, &tcx.types.err, def_bm, discrim_span); self.check_pat(elem, &tcx.types.err, def_bm, ti);
} }
tcx.mk_tup(element_tys_iter) tcx.mk_tup(element_tys_iter)
} else { } else {
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, discrim_span); self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, ti);
} }
pat_ty pat_ty
} }
@ -869,6 +911,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &'tcx [hir::FieldPat<'tcx>], fields: &'tcx [hir::FieldPat<'tcx>],
etc: bool, etc: bool,
def_bm: BindingMode, def_bm: BindingMode,
ti: TopInfo<'tcx>,
) -> bool { ) -> bool {
let tcx = self.tcx; let tcx = self.tcx;
@ -918,7 +961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
}; };
self.check_pat(&field.pat, field_ty, def_bm, None); self.check_pat(&field.pat, field_ty, def_bm, ti);
} }
let mut unmentioned_fields = variant let mut unmentioned_fields = variant
@ -1095,7 +1138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
inner: &'tcx Pat<'tcx>, inner: &'tcx Pat<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) { let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) {
@ -1106,12 +1149,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: inner.span, span: inner.span,
}); });
let box_ty = tcx.mk_box(inner_ty); let box_ty = tcx.mk_box(inner_ty);
self.demand_eqtype_pat(span, expected, box_ty, discrim_span); self.demand_eqtype_pat(span, expected, box_ty, ti);
(box_ty, inner_ty) (box_ty, inner_ty)
} else { } else {
(tcx.types.err, tcx.types.err) (tcx.types.err, tcx.types.err)
}; };
self.check_pat(&inner, inner_ty, def_bm, discrim_span); self.check_pat(&inner, inner_ty, def_bm, ti);
box_ty box_ty
} }
@ -1122,7 +1165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mutbl: hir::Mutability, mutbl: hir::Mutability,
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
let expected = self.shallow_resolve(expected); let expected = self.shallow_resolve(expected);
@ -1157,7 +1200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else { } else {
(tcx.types.err, tcx.types.err) (tcx.types.err, tcx.types.err)
}; };
self.check_pat(&inner, inner_ty, def_bm, discrim_span); self.check_pat(&inner, inner_ty, def_bm, ti);
rptr_ty rptr_ty
} }
@ -1186,7 +1229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
after: &'tcx [&'tcx Pat<'tcx>], after: &'tcx [&'tcx Pat<'tcx>],
expected: Ty<'tcx>, expected: Ty<'tcx>,
def_bm: BindingMode, def_bm: BindingMode,
discrim_span: Option<Span>, ti: TopInfo<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
let err = self.tcx.types.err; let err = self.tcx.types.err;
let expected = self.structurally_resolved_type(span, expected); let expected = self.structurally_resolved_type(span, expected);
@ -1211,15 +1254,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type check all the patterns before `slice`. // Type check all the patterns before `slice`.
for elt in before { for elt in before {
self.check_pat(&elt, inner_ty, def_bm, discrim_span); self.check_pat(&elt, inner_ty, def_bm, ti);
} }
// Type check the `slice`, if present, against its expected type. // Type check the `slice`, if present, against its expected type.
if let Some(slice) = slice { if let Some(slice) = slice {
self.check_pat(&slice, slice_ty, def_bm, discrim_span); self.check_pat(&slice, slice_ty, def_bm, ti);
} }
// Type check the elements after `slice`, if present. // Type check the elements after `slice`, if present.
for elt in after { for elt in after {
self.check_pat(&elt, inner_ty, def_bm, discrim_span); self.check_pat(&elt, inner_ty, def_bm, ti);
} }
expected expected
} }

View file

@ -65,6 +65,7 @@ This API is completely unstable and subject to change.
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(nll)] #![feature(nll)]
#![feature(slice_patterns)] #![feature(slice_patterns)]
#![feature(try_blocks)]
#![feature(never_type)] #![feature(never_type)]
#![recursion_limit = "256"] #![recursion_limit = "256"]

View file

@ -10,7 +10,7 @@ error[E0308]: mismatched types
--> $DIR/issue-13624.rs:20:9 --> $DIR/issue-13624.rs:20:9
| |
LL | match enum_struct_variant { LL | match enum_struct_variant {
| ------------------- this match expression has type `()` | ------------------- this expression has type `()`
LL | a::Enum::EnumStructVariant { x, y, z } => { LL | a::Enum::EnumStructVariant { x, y, z } => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum`

View file

@ -44,7 +44,9 @@ error[E0308]: mismatched types
--> $DIR/destructure-trait-ref.rs:42:13 --> $DIR/destructure-trait-ref.rs:42:13
| |
LL | let box box x = box 1isize as Box<dyn T>; LL | let box box x = box 1isize as Box<dyn T>;
| ^^^^^ expected trait `T`, found struct `std::boxed::Box` | ^^^^^ ------------------------ this expression has type `std::boxed::Box<dyn T>`
| |
| expected trait `T`, found struct `std::boxed::Box`
| |
= note: expected trait object `dyn T` = note: expected trait object `dyn T`
found struct `std::boxed::Box<_>` found struct `std::boxed::Box<_>`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/E0308-4.rs:4:15 --> $DIR/E0308-4.rs:4:15
| |
LL | match x { LL | match x {
| - this match expression has type `u8` | - this expression has type `u8`
LL | 0u8..=3i8 => (), LL | 0u8..=3i8 => (),
| --- ^^^ expected `u8`, found `i8` | --- ^^^ expected `u8`, found `i8`
| | | |

View file

@ -8,7 +8,7 @@ error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13 --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
| |
LL | match [5..4, 99..105, 43..44] { LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>` | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [_, 99.., _] => {}, LL | [_, 99.., _] => {},
| ^^ expected struct `std::ops::Range`, found integer | ^^ expected struct `std::ops::Range`, found integer
| |

View file

@ -14,7 +14,7 @@ error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13 --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
| |
LL | match [5..4, 99..105, 43..44] { LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>` | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [_, 99..] => {}, LL | [_, 99..] => {},
| ^^ expected struct `std::ops::Range`, found integer | ^^ expected struct `std::ops::Range`, found integer
| |

View file

@ -8,7 +8,7 @@ error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12
| |
LL | match [5..4, 99..105, 43..44] { LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>` | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {}, LL | [..9, 99..100, _] => {},
| ^ expected struct `std::ops::Range`, found integer | ^ expected struct `std::ops::Range`, found integer
| |
@ -19,7 +19,7 @@ error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15 --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15
| |
LL | match [5..4, 99..105, 43..44] { LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>` | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {}, LL | [..9, 99..100, _] => {},
| ^^ --- this is of type `{integer}` | ^^ --- this is of type `{integer}`
| | | |
@ -32,7 +32,7 @@ error[E0308]: mismatched types
--> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19 --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19
| |
LL | match [5..4, 99..105, 43..44] { LL | match [5..4, 99..105, 43..44] {
| ----------------------- this match expression has type `std::ops::Range<{integer}>` | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
LL | [..9, 99..100, _] => {}, LL | [..9, 99..100, _] => {},
| -- ^^^ expected struct `std::ops::Range`, found integer | -- ^^^ expected struct `std::ops::Range`, found integer
| | | |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-11844.rs:6:9 --> $DIR/issue-11844.rs:6:9
| |
LL | match a { LL | match a {
| - this match expression has type `std::option::Option<std::boxed::Box<{integer}>>` | - this expression has type `std::option::Option<std::boxed::Box<{integer}>>`
LL | Ok(a) => LL | Ok(a) =>
| ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-12552.rs:6:5 --> $DIR/issue-12552.rs:6:5
| |
LL | match t { LL | match t {
| - this match expression has type `std::result::Result<_, {integer}>` | - this expression has type `std::result::Result<_, {integer}>`
LL | Some(k) => match k { LL | Some(k) => match k {
| ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-13466.rs:8:9 --> $DIR/issue-13466.rs:8:9
| |
LL | let _x: usize = match Some(1) { LL | let _x: usize = match Some(1) {
| ------- this match expression has type `std::option::Option<{integer}>` | ------- this expression has type `std::option::Option<{integer}>`
LL | Ok(u) => u, LL | Ok(u) => u,
| ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
| |
@ -13,7 +13,7 @@ error[E0308]: mismatched types
--> $DIR/issue-13466.rs:14:9 --> $DIR/issue-13466.rs:14:9
| |
LL | let _x: usize = match Some(1) { LL | let _x: usize = match Some(1) {
| ------- this match expression has type `std::option::Option<{integer}>` | ------- this expression has type `std::option::Option<{integer}>`
... ...
LL | Err(e) => panic!(e) LL | Err(e) => panic!(e)
| ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`

View file

@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/issue-14541.rs:5:9 --> $DIR/issue-14541.rs:5:9
| |
LL | let Vec3 { y: _, z: _ } = v; LL | let Vec3 { y: _, z: _ } = v;
| ^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found struct `Vec3` | ^^^^^^^^^^^^^^^^^^^ - this expression has type `Vec2`
| |
| expected struct `Vec2`, found struct `Vec3`
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-15896.rs:11:11 --> $DIR/issue-15896.rs:11:11
| |
LL | let u = match e { LL | let u = match e {
| - this match expression has type `main::R` | - this expression has type `main::E`
LL | E::B( LL | E::B(
LL | Tau{t: x}, LL | Tau{t: x},
| ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau`

View file

@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/issue-16338.rs:7:9 --> $DIR/issue-16338.rs:7:9
| |
LL | let Slice { data: data, len: len } = "foo"; LL | let Slice { data: data, len: len } = "foo";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `str`, found struct `Slice` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----- this expression has type `&str`
| |
| expected `str`, found struct `Slice`
| |
= note: expected type `str` = note: expected type `str`
found struct `Slice<_>` found struct `Slice<_>`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-16401.rs:8:9 --> $DIR/issue-16401.rs:8:9
| |
LL | match () { LL | match () {
| -- this match expression has type `()` | -- this expression has type `()`
LL | Slice { data: data, len: len } => (), LL | Slice { data: data, len: len } => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Slice` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Slice`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-3680.rs:3:9 --> $DIR/issue-3680.rs:3:9
| |
LL | match None { LL | match None {
| ---- this match expression has type `std::option::Option<_>` | ---- this expression has type `std::option::Option<_>`
LL | Err(_) => () LL | Err(_) => ()
| ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result`
| |

View file

@ -8,7 +8,9 @@ error[E0308]: mismatched types
--> $DIR/issue-37026.rs:7:9 --> $DIR/issue-37026.rs:7:9
| |
LL | let empty_struct::XEmpty6(..) = (); LL | let empty_struct::XEmpty6(..) = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `empty_struct::XEmpty6` | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()`
| |
| expected `()`, found struct `empty_struct::XEmpty6`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -29,7 +29,7 @@ error[E0308]: mismatched types
--> $DIR/issue-5100.rs:33:9 --> $DIR/issue-5100.rs:33:9
| |
LL | match (true, false) { LL | match (true, false) {
| ------------- this match expression has type `(bool, bool)` | ------------- this expression has type `(bool, bool)`
LL | box (true, false) => () LL | box (true, false) => ()
| ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box` | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-5358-1.rs:6:9 --> $DIR/issue-5358-1.rs:6:9
| |
LL | match S(Either::Left(5)) { LL | match S(Either::Left(5)) {
| ------------------ this match expression has type `S` | ------------------ this expression has type `S`
LL | Either::Right(_) => {} LL | Either::Right(_) => {}
| ^^^^^^^^^^^^^^^^ expected struct `S`, found enum `Either` | ^^^^^^^^^^^^^^^^ expected struct `S`, found enum `Either`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-57741-1.rs:14:9 --> $DIR/issue-57741-1.rs:14:9
| |
LL | let y = match x { LL | let y = match x {
| - this match expression has type `std::boxed::Box<u32>` | - this expression has type `std::boxed::Box<u32>`
LL | S::A { a } | S::B { b: a } => a, LL | S::A { a } | S::B { b: a } => a,
| ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
| |
@ -13,7 +13,7 @@ error[E0308]: mismatched types
--> $DIR/issue-57741-1.rs:14:22 --> $DIR/issue-57741-1.rs:14:22
| |
LL | let y = match x { LL | let y = match x {
| - this match expression has type `std::boxed::Box<u32>` | - this expression has type `std::boxed::Box<u32>`
LL | S::A { a } | S::B { b: a } => a, LL | S::A { a } | S::B { b: a } => a,
| ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
| |

View file

@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | let y = match x { LL | let y = match x {
| - | -
| | | |
| this match expression has type `std::boxed::Box<T>` | this expression has type `std::boxed::Box<T>`
| help: consider dereferencing the boxed value: `*x` | help: consider dereferencing the boxed value: `*x`
LL | T::A(a) | T::B(a) => a, LL | T::A(a) | T::B(a) => a,
| ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
@ -18,7 +18,7 @@ error[E0308]: mismatched types
LL | let y = match x { LL | let y = match x {
| - | -
| | | |
| this match expression has type `std::boxed::Box<T>` | this expression has type `std::boxed::Box<T>`
| help: consider dereferencing the boxed value: `*x` | help: consider dereferencing the boxed value: `*x`
LL | T::A(a) | T::B(a) => a, LL | T::A(a) | T::B(a) => a,
| ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
@ -32,7 +32,7 @@ error[E0308]: mismatched types
LL | let y = match x { LL | let y = match x {
| - | -
| | | |
| this match expression has type `std::boxed::Box<S>` | this expression has type `std::boxed::Box<S>`
| help: consider dereferencing the boxed value: `*x` | help: consider dereferencing the boxed value: `*x`
LL | S::A { a } | S::B { b: a } => a, LL | S::A { a } | S::B { b: a } => a,
| ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
@ -46,7 +46,7 @@ error[E0308]: mismatched types
LL | let y = match x { LL | let y = match x {
| - | -
| | | |
| this match expression has type `std::boxed::Box<S>` | this expression has type `std::boxed::Box<S>`
| help: consider dereferencing the boxed value: `*x` | help: consider dereferencing the boxed value: `*x`
LL | S::A { a } | S::B { b: a } => a, LL | S::A { a } | S::B { b: a } => a,
| ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`

View file

@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9 --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
| |
LL | let P() = U {}; LL | let P() = U {};
| ^^^ expected struct `U`, found struct `P` | ^^^ ---- this expression has type `U`
| |
| expected struct `U`, found struct `P`
| |
= note: expected struct `U` = note: expected struct `U`
found struct `P<_>` found struct `P<_>`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-7092.rs:6:9 --> $DIR/issue-7092.rs:6:9
| |
LL | match x { LL | match x {
| - this match expression has type `Whatever` | - this expression has type `Whatever`
LL | Some(field) => LL | Some(field) =>
| ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option` | ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option`
| |

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/match-struct.rs:6:9 --> $DIR/match-struct.rs:6:9
| |
LL | match (S { a: 1 }) { LL | match (S { a: 1 }) {
| ------------ this match expression has type `S` | ------------ this expression has type `S`
LL | E::C(_) => (), LL | E::C(_) => (),
| ^^^^^^^ expected struct `S`, found enum `E` | ^^^^^^^ expected struct `S`, found enum `E`

View file

@ -4,7 +4,7 @@ error[E0308]: mismatched types
LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } }
| - ^^^^^^^ expected enum `A`, found enum `B` | - ^^^^^^^ expected enum `A`, found enum `B`
| | | |
| this match expression has type `A` | this expression has type `A`
error: aborting due to previous error error: aborting due to previous error

View file

@ -9,6 +9,8 @@ LL | (0, ref y) | (y, 0) => {}
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/E0409.rs:5:23 --> $DIR/E0409.rs:5:23
| |
LL | match x {
| - this expression has type `({integer}, {integer})`
LL | (0, ref y) | (y, 0) => {} LL | (0, ref y) | (y, 0) => {}
| ^ expected `&{integer}`, found integer | ^ expected `&{integer}`, found integer

View file

@ -94,7 +94,9 @@ error[E0308]: mismatched types
--> $DIR/already-bound-name.rs:33:31 --> $DIR/already-bound-name.rs:33:31
| |
LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
| ^ expected integer, found enum `E` | ^ ------- this expression has type `E<E<{integer}>>`
| |
| expected integer, found enum `E`
| |
= note: expected type `{integer}` = note: expected type `{integer}`
found type `E<{integer}>` found type `E<{integer}>`

View file

@ -60,7 +60,9 @@ error[E0308]: mismatched types
--> $DIR/inconsistent-modes.rs:13:25 --> $DIR/inconsistent-modes.rs:13:25
| |
LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
| ^^^^^^^^^ types differ in mutability | ^^^^^^^^^ -------------------- expected due to this
| |
| types differ in mutability
| |
= note: expected type `&&u8` = note: expected type `&&u8`
found type `&mut &mut u8` found type `&mut &mut u8`
@ -69,7 +71,9 @@ error[E0308]: mismatched types
--> $DIR/inconsistent-modes.rs:16:31 --> $DIR/inconsistent-modes.rs:16:31
| |
LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
| ^^^^^^^^^ types differ in mutability | ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>`
| |
| types differ in mutability
| |
= note: expected type `&{integer}` = note: expected type `&{integer}`
found type `&mut _` found type `&mut _`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/or-pattern-mismatch.rs:3:68 --> $DIR/or-pattern-mismatch.rs:3:68
| |
LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } }
| ^ expected `usize`, found `isize` | ---------------- this expression has type `Blah` ^ expected `usize`, found `isize`
error: aborting due to previous error error: aborting due to previous error

View file

@ -17,7 +17,7 @@ error[E0308]: mismatched types
--> $DIR/pat-tuple-5.rs:5:10 --> $DIR/pat-tuple-5.rs:5:10
| |
LL | match (0, 1) { LL | match (0, 1) {
| ------ this match expression has type `({integer}, {integer})` | ------ this expression has type `({integer}, {integer})`
LL | (PAT ..) => {} LL | (PAT ..) => {}
| ^^^ expected tuple, found `u8` | ^^^ expected tuple, found `u8`
| |

View file

@ -425,8 +425,9 @@ error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:23:16 --> $DIR/recover-range-pats.rs:23:16
| |
LL | if let X.. .0 = 0 {} LL | if let X.. .0 = 0 {}
| - ^^ expected integer, found floating-point number | - ^^ - this expression has type `u8`
| | | | |
| | expected integer, found floating-point number
| this is of type `u8` | this is of type `u8`
error[E0029]: only char and numeric types are allowed in range patterns error[E0029]: only char and numeric types are allowed in range patterns
@ -457,8 +458,9 @@ error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:36:16 --> $DIR/recover-range-pats.rs:36:16
| |
LL | if let X..=.0 = 0 {} LL | if let X..=.0 = 0 {}
| - ^^ expected integer, found floating-point number | - ^^ - this expression has type `u8`
| | | | |
| | expected integer, found floating-point number
| this is of type `u8` | this is of type `u8`
error[E0029]: only char and numeric types are allowed in range patterns error[E0029]: only char and numeric types are allowed in range patterns
@ -489,8 +491,9 @@ error[E0308]: mismatched types
--> $DIR/recover-range-pats.rs:52:17 --> $DIR/recover-range-pats.rs:52:17
| |
LL | if let X... .0 = 0 {} LL | if let X... .0 = 0 {}
| - ^^ expected integer, found floating-point number | - ^^ - this expression has type `u8`
| | | | |
| | expected integer, found floating-point number
| this is of type `u8` | this is of type `u8`
error[E0029]: only char and numeric types are allowed in range patterns error[E0029]: only char and numeric types are allowed in range patterns

View file

@ -0,0 +1,9 @@
struct S {
f: u8,
}
fn main() {
match (S { f: 42 }) {
S { f: Ok(_) } => {} //~ ERROR mismatched types
}
}

View file

@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/pat-struct-field-expr-has-type.rs:7:16
|
LL | match (S { f: 42 }) {
| ------------- this expression has type `S`
LL | S { f: Ok(_) } => {}
| ^^^^^ expected `u8`, found enum `std::result::Result`
|
= note: expected type `u8`
found enum `std::result::Result<_, _>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,8 @@
// Test the `.span_label(..)` to the type when there's a
// type error in a pattern due to a the formal parameter.
fn main() {}
struct Tuple(u8);
fn foo(Tuple(_): String) {} //~ ERROR mismatched types

View file

@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/pat-type-err-formal-param.rs:8:8
|
LL | fn foo(Tuple(_): String) {}
| ^^^^^^^^ ------ expected due to this
| |
| expected struct `std::string::String`, found struct `Tuple`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,16 @@
// Test the `.span_label` to the type / scrutinee
// when there's a type error in checking a pattern.
fn main() {
// We want to point at the `Option<u8>`.
let Ok(0): Option<u8> = 42u8;
//~^ ERROR mismatched types
//~| ERROR mismatched types
// We want to point at the `Option<u8>`.
let Ok(0): Option<u8>;
//~^ ERROR mismatched types
// We want to point at the scrutinee.
let Ok(0) = 42u8; //~ ERROR mismatched types
}

View file

@ -0,0 +1,49 @@
error[E0308]: mismatched types
--> $DIR/pat-type-err-let-stmt.rs:6:29
|
LL | let Ok(0): Option<u8> = 42u8;
| ---------- ^^^^
| | |
| | expected enum `std::option::Option`, found `u8`
| | help: try using a variant of the expected enum: `Some(42u8)`
| expected due to this
|
= note: expected enum `std::option::Option<u8>`
found type `u8`
error[E0308]: mismatched types
--> $DIR/pat-type-err-let-stmt.rs:6:9
|
LL | let Ok(0): Option<u8> = 42u8;
| ^^^^^ ---------- expected due to this
| |
| expected enum `std::option::Option`, found enum `std::result::Result`
|
= note: expected enum `std::option::Option<u8>`
found enum `std::result::Result<_, _>`
error[E0308]: mismatched types
--> $DIR/pat-type-err-let-stmt.rs:11:9
|
LL | let Ok(0): Option<u8>;
| ^^^^^ ---------- expected due to this
| |
| expected enum `std::option::Option`, found enum `std::result::Result`
|
= note: expected enum `std::option::Option<u8>`
found enum `std::result::Result<_, _>`
error[E0308]: mismatched types
--> $DIR/pat-type-err-let-stmt.rs:15:9
|
LL | let Ok(0) = 42u8;
| ^^^^^ ---- this expression has type `u8`
| |
| expected `u8`, found enum `std::result::Result`
|
= note: expected type `u8`
found enum `std::result::Result<_, _>`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -28,7 +28,7 @@ error[E0308]: mismatched types
--> $DIR/pattern-error-continue.rs:22:9 --> $DIR/pattern-error-continue.rs:22:9
| |
LL | match 'c' { LL | match 'c' {
| --- this match expression has type `char` | --- this expression has type `char`
LL | S { .. } => (), LL | S { .. } => (),
| ^^^^^^^^ expected `char`, found struct `S` | ^^^^^^^^ expected `char`, found struct `S`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/pattern-tyvar.rs:5:18 --> $DIR/pattern-tyvar.rs:5:18
| |
LL | match t { LL | match t {
| - this match expression has type `std::option::Option<std::vec::Vec<isize>>` | - this expression has type `Bar`
LL | Bar::T1(_, Some::<isize>(x)) => { LL | Bar::T1(_, Some::<isize>(x)) => {
| ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize` | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize`
| |

View file

@ -23,18 +23,24 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {}
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-binding-mode.rs:7:32 --> $DIR/resolve-inconsistent-binding-mode.rs:7:32
| |
LL | match x {
| - this expression has type `Opts`
LL | Opts::A(ref i) | Opts::B(i) => {} LL | Opts::A(ref i) | Opts::B(i) => {}
| ^ expected `&isize`, found `isize` | ^ expected `&isize`, found `isize`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-binding-mode.rs:16:32 --> $DIR/resolve-inconsistent-binding-mode.rs:16:32
| |
LL | match x {
| - this expression has type `Opts`
LL | Opts::A(ref i) | Opts::B(i) => {} LL | Opts::A(ref i) | Opts::B(i) => {}
| ^ expected `&isize`, found `isize` | ^ expected `&isize`, found `isize`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-binding-mode.rs:25:36 --> $DIR/resolve-inconsistent-binding-mode.rs:25:36
| |
LL | match x {
| - this expression has type `Opts`
LL | Opts::A(ref mut i) | Opts::B(ref i) => {} LL | Opts::A(ref mut i) | Opts::B(ref i) => {}
| ^^^^^ types differ in mutability | ^^^^^ types differ in mutability
| |

View file

@ -86,6 +86,8 @@ LL | (CONST1, _) | (_, Const2) => ()
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-names.rs:19:19 --> $DIR/resolve-inconsistent-names.rs:19:19
| |
LL | match x {
| - this expression has type `(E, E)`
LL | (A, B) | (ref B, c) | (c, A) => () LL | (A, B) | (ref B, c) | (c, A) => ()
| ^^^^^ expected enum `E`, found `&E` | ^^^^^ expected enum `E`, found `&E`

View file

@ -630,7 +630,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:67:12 --> $DIR/disallowed-positions.rs:67:12
| |
LL | if let Range { start: _, end: _ } = true..true && false {} LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -650,7 +650,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:71:12 --> $DIR/disallowed-positions.rs:71:12
| |
LL | if let Range { start: _, end: _ } = true..true || false {} LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -697,7 +697,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:86:12 --> $DIR/disallowed-positions.rs:86:12
| |
LL | if let Range { start: true, end } = t..&&false {} LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -818,7 +818,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:131:15 --> $DIR/disallowed-positions.rs:131:15
| |
LL | while let Range { start: _, end: _ } = true..true && false {} LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -838,7 +838,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:135:15 --> $DIR/disallowed-positions.rs:135:15
| |
LL | while let Range { start: _, end: _ } = true..true || false {} LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -885,7 +885,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:150:15 --> $DIR/disallowed-positions.rs:150:15
| |
LL | while let Range { start: true, end } = t..&&false {} LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |
@ -961,7 +961,7 @@ error[E0308]: mismatched types
--> $DIR/disallowed-positions.rs:198:10 --> $DIR/disallowed-positions.rs:198:10
| |
LL | (let Range { start: _, end: _ } = true..true || false); LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
| | | |
| expected `bool`, found struct `std::ops::Range` | expected `bool`, found struct `std::ops::Range`
| |

View file

@ -86,7 +86,7 @@ error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:54:9 --> $DIR/structure-constructor-type-mismatch.rs:54:9
| |
LL | match (Point { x: 1, y: 2 }) { LL | match (Point { x: 1, y: 2 }) {
| ---------------------- this match expression has type `Point<{integer}>` | ---------------------- this expression has type `Point<{integer}>`
LL | PointF::<u32> { .. } => {} LL | PointF::<u32> { .. } => {}
| ^^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` | ^^^^^^^^^^^^^^^^^^^^ expected integer, found `f32`
| |
@ -97,7 +97,7 @@ error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:59:9 --> $DIR/structure-constructor-type-mismatch.rs:59:9
| |
LL | match (Point { x: 1, y: 2 }) { LL | match (Point { x: 1, y: 2 }) {
| ---------------------- this match expression has type `Point<{integer}>` | ---------------------- this expression has type `Point<{integer}>`
LL | PointF { .. } => {} LL | PointF { .. } => {}
| ^^^^^^^^^^^^^ expected integer, found `f32` | ^^^^^^^^^^^^^ expected integer, found `f32`
| |
@ -108,7 +108,7 @@ error[E0308]: mismatched types
--> $DIR/structure-constructor-type-mismatch.rs:67:9 --> $DIR/structure-constructor-type-mismatch.rs:67:9
| |
LL | match (Pair { x: 1, y: 2 }) { LL | match (Pair { x: 1, y: 2 }) {
| --------------------- this match expression has type `Pair<{integer}, {integer}>` | --------------------- this expression has type `Pair<{integer}, {integer}>`
LL | PairF::<u32> { .. } => {} LL | PairF::<u32> { .. } => {}
| ^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` | ^^^^^^^^^^^^^^^^^^^ expected integer, found `f32`
| |