Auto merge of #42642 - venkatagiri:issue_42312, r=nikomatsakis
rustc_typeck: enforce argument type is sized closes #42312 r? @nikomatsakis
This commit is contained in:
commit
0816b94f02
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use hir::{self, map, Local, Pat, Body};
|
||||
use hir::{self, Local, Pat, Body};
|
||||
use hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use infer::InferCtxt;
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) {
|
||||
pub fn need_type_info(&self, body_id: Option<hir::BodyId>, span: Span, ty: Ty<'tcx>) {
|
||||
let ty = self.resolve_type_vars_if_possible(&ty);
|
||||
let name = self.extract_type_name(&ty);
|
||||
|
||||
@ -103,11 +103,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
found_arg_pattern: None,
|
||||
};
|
||||
|
||||
// #40294: cause.body_id can also be a fn declaration.
|
||||
// Currently, if it's anything other than NodeExpr, we just ignore it
|
||||
match self.tcx.hir.find(body_id.node_id) {
|
||||
Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr),
|
||||
_ => ()
|
||||
if let Some(body_id) = body_id {
|
||||
let expr = self.tcx.hir.expect_expr(body_id.node_id);
|
||||
local_visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||
|
@ -45,7 +45,8 @@ use syntax_pos::{DUMMY_SP, Span};
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn report_fulfillment_errors(&self,
|
||||
errors: &Vec<FulfillmentError<'tcx>>) {
|
||||
errors: &Vec<FulfillmentError<'tcx>>,
|
||||
body_id: Option<hir::BodyId>) {
|
||||
#[derive(Debug)]
|
||||
struct ErrorDescriptor<'tcx> {
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
@ -105,7 +106,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
for (error, suppressed) in errors.iter().zip(is_suppressed) {
|
||||
if !suppressed {
|
||||
self.report_fulfillment_error(error);
|
||||
self.report_fulfillment_error(error, body_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +149,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
false
|
||||
}
|
||||
|
||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
|
||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>,
|
||||
body_id: Option<hir::BodyId>) {
|
||||
debug!("report_fulfillment_errors({:?})", error);
|
||||
match error.code {
|
||||
FulfillmentErrorCode::CodeSelectionError(ref e) => {
|
||||
@ -158,7 +160,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.report_projection_error(&error.obligation, e);
|
||||
}
|
||||
FulfillmentErrorCode::CodeAmbiguity => {
|
||||
self.maybe_report_ambiguity(&error.obligation);
|
||||
self.maybe_report_ambiguity(&error.obligation, body_id);
|
||||
}
|
||||
FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
|
||||
self.report_mismatched_types(&error.obligation.cause,
|
||||
@ -869,14 +871,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
|
||||
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>,
|
||||
body_id: Option<hir::BodyId>) {
|
||||
// Unable to successfully determine, probably means
|
||||
// insufficient type information, but could mean
|
||||
// ambiguous impls. The latter *ought* to be a
|
||||
// coherence violation, so we don't report it here.
|
||||
|
||||
let predicate = self.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
let body_id = hir::BodyId { node_id: obligation.cause.body_id };
|
||||
let span = obligation.cause.span;
|
||||
|
||||
debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
|
||||
@ -953,7 +955,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
|
||||
// both must be type variables, or the other would've been instantiated
|
||||
assert!(a.is_ty_var() && b.is_ty_var());
|
||||
self.need_type_info(hir::BodyId { node_id: obligation.cause.body_id },
|
||||
self.need_type_info(body_id,
|
||||
obligation.cause.span,
|
||||
a);
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
) {
|
||||
Ok(predicates) => predicates,
|
||||
Err(errors) => {
|
||||
infcx.report_fulfillment_errors(&errors);
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
// An unnormalized env is better than nothing.
|
||||
return elaborated_env;
|
||||
}
|
||||
|
@ -996,7 +996,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
||||
tcx.require_lang_item(lang_items::SyncTraitLangItem),
|
||||
cause);
|
||||
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(&err);
|
||||
infcx.report_fulfillment_errors(&err, None);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors);
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
@ -793,7 +793,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(errors);
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||
|
||||
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||
// this could be reached when we get lazy normalization
|
||||
infcx.report_fulfillment_errors(errors);
|
||||
infcx.report_fulfillment_errors(errors, None);
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,8 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
/// environment is for an item or something where the "callee" is
|
||||
/// not clear.
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
|
||||
body_id: Option<hir::BodyId>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
|
||||
@ -605,6 +607,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
|
||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||
anon_types: RefCell::new(NodeMap()),
|
||||
implicit_region_bound,
|
||||
body_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -993,16 +996,17 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
|
||||
|
||||
// Add formal parameters.
|
||||
for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
|
||||
// The type of the argument must be well-formed.
|
||||
//
|
||||
// NB -- this is now checked in wfcheck, but that
|
||||
// currently only results in warnings, so we issue an
|
||||
// old-style WF obligation here so that we still get the
|
||||
// errors that we used to get.
|
||||
fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
|
||||
|
||||
// Check the pattern.
|
||||
fcx.check_pat_arg(&arg.pat, arg_ty, true);
|
||||
|
||||
// Check that argument is Sized.
|
||||
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
|
||||
// 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`.
|
||||
if arg.pat.simple_name().is_none() {
|
||||
fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::MiscObligation);
|
||||
}
|
||||
|
||||
fcx.write_ty(arg.id, arg_ty);
|
||||
}
|
||||
|
||||
@ -1978,17 +1982,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers an obligation for checking later, during regionck, that the type `ty` must
|
||||
/// outlive the region `r`.
|
||||
pub fn register_region_obligation(&self,
|
||||
ty: Ty<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
cause: traits::ObligationCause<'tcx>)
|
||||
{
|
||||
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
|
||||
fulfillment_cx.register_region_obligation(ty, region, cause);
|
||||
}
|
||||
|
||||
/// Registers an obligation for checking later, during regionck, that the type `ty` must
|
||||
/// outlive the region `r`.
|
||||
pub fn register_wf_obligation(&self,
|
||||
@ -2003,21 +1996,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::WellFormed(ty)));
|
||||
}
|
||||
|
||||
pub fn register_old_wf_obligation(&self,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
code: traits::ObligationCauseCode<'tcx>)
|
||||
{
|
||||
// Registers an "old-style" WF obligation that uses the
|
||||
// implicator code. This is basically a buggy version of
|
||||
// `register_wf_obligation` that is being kept around
|
||||
// temporarily just to help with phasing in the newer rules.
|
||||
//
|
||||
// FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
|
||||
let cause = traits::ObligationCause::new(span, self.body_id, code);
|
||||
self.register_region_obligation(ty, self.tcx.types.re_empty, cause);
|
||||
}
|
||||
|
||||
/// Registers obligations that all types appearing in `substs` are well-formed.
|
||||
pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr)
|
||||
{
|
||||
@ -2145,7 +2123,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
match fulfillment_cx.select_all_or_error(self) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { self.report_fulfillment_errors(&errors); }
|
||||
Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2153,7 +2131,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn select_obligations_where_possible(&self) {
|
||||
match self.fulfillment_cx.borrow_mut().select_where_possible(self) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { self.report_fulfillment_errors(&errors); }
|
||||
Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +377,7 @@ impl<'cx, 'gcx, 'tcx> Resolver<'cx, 'gcx, 'tcx> {
|
||||
|
||||
fn report_error(&self, t: Ty<'tcx>) {
|
||||
if !self.tcx.sess.has_errors() {
|
||||
self.infcx.need_type_info(self.body.id(), self.span.to_span(&self.tcx), t);
|
||||
self.infcx.need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
// Check that all transitive obligations are satisfied.
|
||||
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
|
||||
infcx.report_fulfillment_errors(&errors);
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
}
|
||||
|
||||
// Finally, resolve all regions.
|
||||
|
@ -166,7 +166,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
match fulfill_cx.select_all_or_error(infcx) {
|
||||
Ok(()) => true,
|
||||
Err(errors) => {
|
||||
infcx.report_fulfillment_errors(&errors);
|
||||
infcx.report_fulfillment_errors(&errors, None);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let ex = |x| {
|
||||
let_(add(x,x), |y| { //~ ERROR type annotations needed
|
||||
let ex = |x| { //~ ERROR type annotations needed
|
||||
let_(add(x,x), |y| {
|
||||
let_(add(x, x), |x|x)})};
|
||||
}
|
||||
|
@ -8,9 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn _test(ref _p: str) {}
|
||||
//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied [E0277]
|
||||
|
||||
#[rustc_error]
|
||||
fn main() { } //~ ERROR compilation successful
|
||||
fn main() { }
|
||||
|
21
src/test/compile-fail/issue-42312.rs
Normal file
21
src/test/compile-fail/issue-42312.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
pub trait Foo {
|
||||
fn baz(_: Self::Target) where Self: Deref {}
|
||||
//~^ ERROR `<Self as std::ops::Deref>::Target: std::marker::Sized` is not satisfied
|
||||
}
|
||||
|
||||
pub fn f(_: ToString) {}
|
||||
//~^ ERROR the trait bound `std::string::ToString + 'static: std::marker::Sized` is not satisfied
|
||||
|
||||
fn main() { }
|
@ -15,8 +15,6 @@ use std::ops::Deref;
|
||||
pub trait Foo {
|
||||
type A;
|
||||
fn boo(&self) -> Self::A;
|
||||
|
||||
fn baz(_: Self::Target) where Self: Deref {}
|
||||
}
|
||||
|
||||
impl Foo for isize {
|
||||
|
Loading…
Reference in New Issue
Block a user