Skip to content
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

Short-cut T: Sized trait selection for ADTs #33138

Merged
merged 12 commits into from
May 6, 2016
2 changes: 1 addition & 1 deletion src/libcore/num/bignum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use mem;
use intrinsics;

/// Arithmetic operations required by bignums.
pub trait FullOps {
pub trait FullOps: Sized {
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
/// where `W` is the number of bits in `Self`.
fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum DepNode<D: Clone + Debug> {
ImplOrTraitItems(D),
ItemSignature(D),
FieldTy(D),
SizedConstraint(D),
TraitItemDefIds(D),
InherentImpls(D),
ImplItems(D),
Expand Down Expand Up @@ -193,6 +194,7 @@ impl<D: Clone + Debug> DepNode<D> {
ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
ItemSignature(ref d) => op(d).map(ItemSignature),
FieldTy(ref d) => op(d).map(FieldTy),
SizedConstraint(ref d) => op(d).map(SizedConstraint),
TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
ImplItems(ref d) => op(d).map(ImplItems),
Expand Down
11 changes: 11 additions & 0 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
r
}

// Execute `f` in a snapshot, and commit the bindings it creates
pub fn in_snapshot<T, F>(&self, f: F) -> T where
F: FnOnce(&CombinedSnapshot) -> T
{
debug!("in_snapshot()");
let snapshot = self.start_snapshot();
let r = f(&snapshot);
self.commit_from(snapshot);
r
}

/// Execute `f` and commit only the region bindings if successful.
/// The function f must be very careful not to leak any non-region
/// variables that get created.
Expand Down
16 changes: 15 additions & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ declare_lint! {
"detects super or self keywords at the beginning of global path"
}

declare_lint! {
pub UNSIZED_IN_TUPLE,
Warn,
"unsized types in the interior of a tuple were erroneously allowed"
}

declare_lint! {
pub OBJECT_UNSAFE_FRAGMENT,
Warn,
"object-unsafe non-principal fragments in object types were erroneously allowed"
}

/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -220,7 +232,9 @@ impl LintPass for HardwiredLints {
TRANSMUTE_FROM_FN_ITEM_TYPES,
OVERLAPPING_INHERENT_IMPLS,
RENAMED_AND_REMOVED_LINTS,
SUPER_OR_SELF_IN_GLOBAL_PATH
SUPER_OR_SELF_IN_GLOBAL_PATH,
UNSIZED_IN_TUPLE,
OBJECT_UNSAFE_FRAGMENT
)
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl FreeRegionMap {
match *predicate {
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Rfc1592(..) |
ty::Predicate::Equate(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
Expand Down
156 changes: 116 additions & 40 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,51 @@ use util::nodemap::{FnvHashMap, FnvHashSet};
use std::cmp;
use std::fmt;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
use syntax::ast;
use syntax::codemap::Span;
use syntax::errors::DiagnosticBuilder;

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> {
span: Span,
warning_node_id: Option<ast::NodeId>,
predicate: ty::Predicate<'tcx>
}

impl<'tcx> TraitErrorKey<'tcx> {
fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
e: &FulfillmentError<'tcx>) -> Self {
e: &FulfillmentError<'tcx>,
warning_node_id: Option<ast::NodeId>) -> Self {
let predicate =
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
TraitErrorKey {
span: e.obligation.cause.span,
predicate: infcx.tcx.erase_regions(&predicate)
predicate: infcx.tcx.erase_regions(&predicate),
warning_node_id: warning_node_id
}
}
}

pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
errors: &Vec<FulfillmentError<'tcx>>) {
for error in errors {
report_fulfillment_error(infcx, error);
report_fulfillment_error(infcx, error, None);
}
}

pub fn report_fulfillment_errors_as_warnings<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
errors: &Vec<FulfillmentError<'tcx>>,
node_id: ast::NodeId)
{
for error in errors {
report_fulfillment_error(infcx, error, Some(node_id));
}
}

fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
error: &FulfillmentError<'tcx>) {
let error_key = TraitErrorKey::from_error(infcx, error);
error: &FulfillmentError<'tcx>,
warning_node_id: Option<ast::NodeId>) {
let error_key = TraitErrorKey::from_error(infcx, error, warning_node_id);
debug!("report_fulfillment_errors({:?}) - key={:?}",
error, error_key);
if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
Expand All @@ -75,10 +89,10 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref e) => {
report_selection_error(infcx, &error.obligation, e);
report_selection_error(infcx, &error.obligation, e, warning_node_id);
}
FulfillmentErrorCode::CodeProjectionError(ref e) => {
report_projection_error(infcx, &error.obligation, e);
report_projection_error(infcx, &error.obligation, e, warning_node_id);
}
FulfillmentErrorCode::CodeAmbiguity => {
maybe_report_ambiguity(infcx, &error.obligation);
Expand All @@ -88,18 +102,29 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,

pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>)
error: &MismatchedProjectionTypes<'tcx>,
warning_node_id: Option<ast::NodeId>)
{
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);

if !predicate.references_error() {
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
predicate,
error.err);
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
if let Some(warning_node_id) = warning_node_id {
infcx.tcx.sess.add_lint(
::lint::builtin::UNSIZED_IN_TUPLE,
warning_node_id,
obligation.cause.span,
format!("type mismatch resolving `{}`: {}",
predicate,
error.err));
} else {
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
predicate,
error.err);
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
}
}
}

Expand Down Expand Up @@ -383,7 +408,8 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>,

pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>)
error: &SelectionError<'tcx>,
warning_node_id: Option<ast::NodeId>)
{
match *error {
SelectionError::Unimplemented => {
Expand All @@ -401,6 +427,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,

if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() {
let trait_ref = trait_predicate.to_poly_trait_ref();

if let Some(warning_node_id) = warning_node_id {
infcx.tcx.sess.add_lint(
::lint::builtin::UNSIZED_IN_TUPLE,
warning_node_id,
obligation.cause.span,
format!("the trait bound `{}` is not satisfied",
trait_ref.to_predicate()));
return;
}

let mut err = struct_span_err!(
infcx.tcx.sess, obligation.cause.span, E0277,
"the trait bound `{}` is not satisfied",
Expand Down Expand Up @@ -480,12 +517,15 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
ty::Predicate::ObjectSafe(trait_def_id) => {
let violations = object_safety_violations(
infcx.tcx, trait_def_id);
let mut err = report_object_safety_error(infcx.tcx,
obligation.cause.span,
trait_def_id,
violations);
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
let err = report_object_safety_error(infcx.tcx,
obligation.cause.span,
trait_def_id,
warning_node_id,
violations);
if let Some(mut err) = err {
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
}
}

ty::Predicate::ClosureKind(closure_def_id, kind) => {
Expand Down Expand Up @@ -514,6 +554,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
"WF predicate not satisfied for {:?}",
ty);
}

ty::Predicate::Rfc1592(ref data) => {
span_bug!(
obligation.cause.span,
"RFC1592 predicate not satisfied for {:?}",
data);
}
}
}
}
Expand All @@ -537,58 +584,84 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,

TraitNotObjectSafe(did) => {
let violations = object_safety_violations(infcx.tcx, did);
let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
violations);
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
let err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
warning_node_id,
violations);
if let Some(mut err) = err {
note_obligation_cause(infcx, &mut err, obligation);
err.emit();
}
}
}
}

pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>,
span: Span,
trait_def_id: DefId,
warning_node_id: Option<ast::NodeId>,
violations: Vec<ObjectSafetyViolation>)
-> DiagnosticBuilder<'tcx>
-> Option<DiagnosticBuilder<'tcx>>
{
let mut err = struct_span_err!(
tcx.sess, span, E0038,
"the trait `{}` cannot be made into an object",
tcx.item_path_str(trait_def_id));
let mut err = match warning_node_id {
Some(_) => None,
None => {
Some(struct_span_err!(
tcx.sess, span, E0038,
"the trait `{}` cannot be made into an object",
tcx.item_path_str(trait_def_id)))
}
};

let mut reported_violations = FnvHashSet();
for violation in violations {
if !reported_violations.insert(violation.clone()) {
continue;
}
match violation {
let buf;
let note = match violation {
ObjectSafetyViolation::SizedSelf => {
err.note("the trait cannot require that `Self : Sized`");
"the trait cannot require that `Self : Sized`"
}

ObjectSafetyViolation::SupertraitSelf => {
err.note("the trait cannot use `Self` as a type parameter \
in the supertrait listing");
"the trait cannot use `Self` as a type parameter \
in the supertrait listing"
}

ObjectSafetyViolation::Method(method,
MethodViolationCode::StaticMethod) => {
err.note(&format!("method `{}` has no receiver",
method.name));
buf = format!("method `{}` has no receiver",
method.name);
&buf
}

ObjectSafetyViolation::Method(method,
MethodViolationCode::ReferencesSelf) => {
err.note(&format!("method `{}` references the `Self` type \
buf = format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name));
method.name);
&buf
}

ObjectSafetyViolation::Method(method,
MethodViolationCode::Generic) => {
err.note(&format!("method `{}` has generic type parameters",
method.name));
buf = format!("method `{}` has generic type parameters",
method.name);
&buf
}
};
match (warning_node_id, &mut err) {
(Some(node_id), &mut None) => {
tcx.sess.add_lint(
::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
node_id,
span,
note.to_string());
}
(None, &mut Some(ref mut err)) => {
err.note(note);
}
_ => unreachable!()
}
}
err
Expand Down Expand Up @@ -764,6 +837,9 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
ObligationCauseCode::TupleElem => {
err.note("tuple elements must have `Sized` type");
}
ObligationCauseCode::ProjectionWf(data) => {
err.note(&format!("required so that the projection `{}` is well-formed",
data));
Expand Down
Loading