Skip to content

rustc_typeck: enforce argument type is sized #42642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/librustc/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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 {
Expand Down
16 changes: 9 additions & 7 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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,
Expand Down Expand Up @@ -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={:?})",
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/dropck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
50 changes: 14 additions & 36 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,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> {
Expand Down Expand Up @@ -604,6 +606,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,
}
}

Expand Down Expand Up @@ -992,16 +995,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);
}

Expand Down Expand Up @@ -1977,17 +1981,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,
Expand All @@ -2002,21 +1995,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)
{
Expand Down Expand Up @@ -2144,15 +2122,15 @@ 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); }
}
}

/// Select as many obligations as we can at present.
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); }
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/issue-23046.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)})};
}
6 changes: 2 additions & 4 deletions src/test/compile-fail/issue-38954.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 21 additions & 0 deletions src/test/compile-fail/issue-42312.rs
Original file line number Diff line number Diff line change
@@ -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() { }
2 changes: 0 additions & 2 deletions src/test/run-pass/associated-types-sugar-path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down