diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 66c6deb3615..a881b539ced 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -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); diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 536c739bf16..85b4b4f59c4 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -88,6 +88,7 @@ pub enum DepNode { ImplOrTraitItems(D), ItemSignature(D), FieldTy(D), + SizedConstraint(D), TraitItemDefIds(D), InherentImpls(D), ImplItems(D), @@ -193,6 +194,7 @@ impl DepNode { 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), diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 312a446d440..6da4c44fe9a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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(&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. diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2564838c67d..6dd98425df3 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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)] @@ -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 ) } } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 51eebd43731..758fb7a81fd 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -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(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 531a4fbf8be..b89ce2ce3b2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,23 +36,27 @@ 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, 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) -> 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 } } } @@ -60,13 +64,23 @@ impl<'tcx> TraitErrorKey<'tcx> { pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, errors: &Vec>) { 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>, + 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) { + 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) { @@ -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); @@ -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) { 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(); + } } } @@ -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) { match *error { SelectionError::Unimplemented => { @@ -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", @@ -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) => { @@ -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); + } } } } @@ -537,10 +584,13 @@ 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(); + } } } } @@ -548,47 +598,70 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, span: Span, trait_def_id: DefId, + warning_node_id: Option, violations: Vec) - -> DiagnosticBuilder<'tcx> + -> Option> { - 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 @@ -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)); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 8946ec2153b..a184e951b83 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -13,6 +13,7 @@ use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef}; use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error}; use std::iter; +use std::mem; use syntax::ast; use util::common::ErrorReported; use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; @@ -70,6 +71,9 @@ pub struct FulfillmentContext<'tcx> { predicates: ObligationForest, LocalFulfilledPredicates<'tcx>>, + // A list of new obligations due to RFC1592. + rfc1592_obligations: Vec>, + // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from @@ -116,6 +120,7 @@ impl<'tcx> FulfillmentContext<'tcx> { FulfillmentContext { duplicate_set: LocalFulfilledPredicates::new(), predicates: ObligationForest::new(), + rfc1592_obligations: Vec::new(), region_obligations: NodeMap(), } } @@ -197,6 +202,13 @@ impl<'tcx> FulfillmentContext<'tcx> { self.predicates.push_tree(obligation, LocalFulfilledPredicates::new()); } + pub fn register_rfc1592_obligation<'a>(&mut self, + _infcx: &InferCtxt<'a,'tcx>, + obligation: PredicateObligation<'tcx>) + { + self.rfc1592_obligations.push(obligation); + } + pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] @@ -207,11 +219,26 @@ impl<'tcx> FulfillmentContext<'tcx> { } } + pub fn select_rfc1592_obligations<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>) + -> Result<(),Vec>> + { + while !self.rfc1592_obligations.is_empty() { + for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) { + self.register_predicate_obligation(infcx, obligation); + } + + self.select_all_or_error(infcx)?; + } + + Ok(()) + } pub fn select_all_or_error<'a>(&mut self, infcx: &InferCtxt<'a,'tcx>) -> Result<(),Vec>> { self.select_where_possible(infcx)?; + let errors: Vec<_> = self.predicates.to_errors(CodeAmbiguity) .into_iter() @@ -279,12 +306,14 @@ impl<'tcx> FulfillmentContext<'tcx> { // Process pending obligations. let outcome = { let region_obligations = &mut self.region_obligations; + let rfc1592_obligations = &mut self.rfc1592_obligations; self.predicates.process_obligations( |obligation, tree, backtrace| process_predicate(selcx, - tree, - obligation, - backtrace, - region_obligations)) + tree, + obligation, + backtrace, + region_obligations, + rfc1592_obligations)) }; debug!("select: outcome={:?}", outcome); @@ -321,11 +350,13 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, tree_cache: &mut LocalFulfilledPredicates<'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, backtrace: Backtrace>, - region_obligations: &mut NodeMap>>) + region_obligations: &mut NodeMap>>, + rfc1592_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> { - match process_predicate1(selcx, pending_obligation, region_obligations) { + match process_predicate1(selcx, pending_obligation, region_obligations, + rfc1592_obligations) { Ok(Some(v)) => process_child_obligations(selcx, tree_cache, &pending_obligation.obligation, @@ -507,7 +538,8 @@ fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>, /// - `Err` if the predicate does not hold fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, - region_obligations: &mut NodeMap>>) + region_obligations: &mut NodeMap>>, + rfc1592_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> { @@ -677,6 +709,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, s => Ok(s) } } + + ty::Predicate::Rfc1592(ref inner) => { + rfc1592_obligations.push(PredicateObligation { + predicate: ty::Predicate::clone(inner), + ..obligation.clone() + }); + Ok(Some(vec![])) + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a160465e2e8..7da95b6646a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -28,6 +28,7 @@ use syntax::codemap::{Span, DUMMY_SP}; pub use self::error_reporting::TraitErrorKey; pub use self::error_reporting::recursive_type_with_infinite_size_error; pub use self::error_reporting::report_fulfillment_errors; +pub use self::error_reporting::report_fulfillment_errors_as_warnings; pub use self::error_reporting::report_overflow_error; pub use self::error_reporting::report_overflow_error_cycle; pub use self::error_reporting::report_selection_error; @@ -106,9 +107,12 @@ pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, - /// This is the trait reference from the given projection + /// A slice or array is WF only if `T: Sized` SliceOrArrayElem, + /// A tuple is WF only if its middle elements are Sized + TupleElem, + /// This is the trait reference from the given projection ProjectionWf(ty::ProjectionTy<'tcx>), diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c870d609814..59db68b1c3c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -166,6 +166,7 @@ pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>, ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) => { false } @@ -204,6 +205,7 @@ fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d7528fc3130..138ca7a0f35 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -13,7 +13,6 @@ pub use self::MethodMatchResult::*; pub use self::MethodMatchedData::*; use self::SelectionCandidate::*; -use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; use super::coherence; @@ -50,7 +49,6 @@ use std::fmt; use std::rc::Rc; use syntax::abi::Abi; use hir; -use util::common::ErrorReported; use util::nodemap::FnvHashMap; pub struct SelectionContext<'cx, 'tcx:'cx> { @@ -188,7 +186,7 @@ pub enum MethodMatchedData { /// parameter environment. #[derive(PartialEq,Eq,Debug,Clone)] enum SelectionCandidate<'tcx> { - BuiltinCandidate(ty::BuiltinBound), + BuiltinCandidate { has_nested: bool }, ParamCandidate(ty::PolyTraitRef<'tcx>), ImplCandidate(DefId), DefaultImplCandidate(DefId), @@ -232,10 +230,18 @@ struct EvaluatedCandidate<'tcx> { evaluation: EvaluationResult, } -enum BuiltinBoundConditions<'tcx> { - If(ty::Binder>>), - ParameterBuiltin, - AmbiguousBuiltin +/// When does the builtin impl for `T: Trait` apply? +enum BuiltinImplConditions<'tcx> { + /// The impl is conditional on T1,T2,.. : Trait + Where(ty::Binder>>), + /// There is no built-in impl. There may be some other + /// candidate (a where-clause or user-defined impl). + None, + /// There is *no* impl for this, builtin or not. Ignore + /// all where-clauses. + Never, + /// It is unknown whether there is an impl. + Ambiguous } #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] @@ -412,6 +418,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { + ty::Predicate::Rfc1592(..) => EvaluatedToOk, + ty::Predicate::Trait(ref t) => { assert!(!t.has_escaping_regions()); let obligation = obligation.with(t.clone()); @@ -993,15 +1001,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_impls(obligation, &mut candidates)?; // For other types, we'll use the builtin rules. - self.assemble_builtin_bound_candidates(ty::BoundCopy, - obligation, - &mut candidates)?; + let copy_conditions = self.copy_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; } - Some(bound @ ty::BoundSized) => { + Some(ty::BoundSized) => { // Sized is never implementable by end-users, it is // always automatically computed. - self.assemble_builtin_bound_candidates(bound, - obligation, + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; } @@ -1394,7 +1401,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (self_ty, _) = self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); let poly_trait_ref = match self_ty.sty { @@ -1405,7 +1412,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ pushing candidate"); candidates.vec.push(BuiltinObjectCandidate); - return Ok(()); + return; } } _ => {} @@ -1416,10 +1423,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_candidates_from_object_ty: ambiguous"); candidates.ambiguous = true; // could wind up being an object type - return Ok(()); + return; } _ => { - return Ok(()); + return; } }; @@ -1447,9 +1454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if upcast_trait_refs == 1 { candidates.vec.push(ObjectCandidate); } - - Ok::<(),()>(()) - }).unwrap(); + }) } /// Search for unsizing that might apply to `obligation`. @@ -1570,7 +1575,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinObjectCandidate | BuiltinUnsizeCandidate | DefaultImplObjectCandidate(..) | - BuiltinCandidate(..) => { + BuiltinCandidate { .. } => { // We have a where-clause so don't go around looking // for impls. true @@ -1608,200 +1613,69 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // those will hopefully change to library-defined traits in the // future. + // HACK: if this returns an error, selection exits without considering + // other impls. fn assemble_builtin_bound_candidates<'o>(&mut self, - bound: ty::BuiltinBound, - obligation: &TraitObligation<'tcx>, + conditions: BuiltinImplConditions<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - match self.builtin_bound(bound, obligation) { - Ok(If(..)) => { - debug!("builtin_bound: bound={:?}", - bound); - candidates.vec.push(BuiltinCandidate(bound)); + match conditions { + BuiltinImplConditions::Where(nested) => { + debug!("builtin_bound: nested={:?}", nested); + candidates.vec.push(BuiltinCandidate { + has_nested: nested.skip_binder().len() > 0 + }); Ok(()) } - Ok(ParameterBuiltin) => { Ok(()) } - Ok(AmbiguousBuiltin) => { + BuiltinImplConditions::None => { Ok(()) } + BuiltinImplConditions::Ambiguous => { debug!("assemble_builtin_bound_candidates: ambiguous builtin"); Ok(candidates.ambiguous = true) } - Err(e) => { Err(e) } + BuiltinImplConditions::Never => { Err(Unimplemented) } } } - fn builtin_bound(&mut self, - bound: ty::BuiltinBound, - obligation: &TraitObligation<'tcx>) - -> Result,SelectionError<'tcx>> + fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> { - // Note: these tests operate on types that may contain bound - // regions. To be proper, we ought to skolemize here, but we - // forego the skolemization and defer it until the - // confirmation step. + use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; - let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); - return match self_ty.sty { - ty::TyInfer(ty::IntVar(_)) | - ty::TyInfer(ty::FloatVar(_)) | - ty::TyUint(_) | - ty::TyInt(_) | - ty::TyBool | - ty::TyFloat(_) | - ty::TyFnDef(..) | - ty::TyFnPtr(_) | - ty::TyChar => { + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve( + obligation.predicate.skip_binder().self_ty()); + + match self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | + ty::TyChar | ty::TyBox(_) | ty::TyRef(..) | + ty::TyArray(..) | ty::TyClosure(..) | + ty::TyError => { // safe for everything - ok_if(Vec::new()) + Where(ty::Binder(Vec::new())) } - ty::TyBox(_) => { // Box - match bound { - ty::BoundCopy => Err(Unimplemented), + ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, - ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyRawPtr(..) => { // *const T, *mut T - match bound { - ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyTrait(ref data) => { - match bound { - ty::BoundSized => Err(Unimplemented), - ty::BoundCopy => { - if data.bounds.builtin_bounds.contains(&bound) { - ok_if(Vec::new()) - } else { - // Recursively check all supertraits to find out if any further - // bounds are required and thus we must fulfill. - let principal = - data.principal_trait_ref_with_self_ty(self.tcx(), - self.tcx().types.err); - let copy_def_id = obligation.predicate.def_id(); - for tr in util::supertraits(self.tcx(), principal) { - if tr.def_id() == copy_def_id { - return ok_if(Vec::new()) - } - } - - Err(Unimplemented) - } - } - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl }) => { - // &mut T or &T - match bound { - ty::BoundCopy => { - match mutbl { - // &mut T is affine and hence never `Copy` - hir::MutMutable => Err(Unimplemented), - - // &T is always copyable - hir::MutImmutable => ok_if(Vec::new()), - } - } - - ty::BoundSized => ok_if(Vec::new()), - - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyArray(element_ty, _) => { - // [T; n] - match bound { - ty::BoundCopy => ok_if(vec![element_ty]), - ty::BoundSized => ok_if(Vec::new()), - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyStr | ty::TySlice(_) => { - match bound { - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - - ty::BoundCopy | ty::BoundSized => Err(Unimplemented), - } - } - - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::TyTuple(ref tys) => ok_if(tys.clone()), - - ty::TyClosure(_, ref substs) => { - // FIXME -- This case is tricky. In the case of by-ref - // closures particularly, we need the results of - // inference to decide how to reflect the type of each - // upvar (the upvar may have type `T`, but the runtime - // type could be `&mut`, `&`, or just `T`). For now, - // though, we'll do this unsoundly and assume that all - // captures are by value. Really what we ought to do - // is reserve judgement and then intertwine this - // analysis with closure inference. - - // Unboxed closures shouldn't be - // implicitly copyable - if bound == ty::BoundCopy { - return Ok(ParameterBuiltin); - } - - // Upvars are always local variables or references to - // local variables, and local variables cannot be - // unsized, so the closure struct as a whole must be - // Sized. - if bound == ty::BoundSized { - return ok_if(Vec::new()); - } - - ok_if(substs.upvar_tys.clone()) + ty::TyTuple(ref tys) => { + // FIXME(#33242) we only need to constrain the last field + Where(ty::Binder(tys.clone())) } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { - let types: Vec = def.all_fields().map(|f| { - f.ty(self.tcx(), substs) - }).collect(); - nominal(bound, types) + let sized_crit = def.sized_constraint(self.tcx()); + // (*) binder moved here + Where(ty::Binder(match sized_crit.sty { + ty::TyTuple(ref tys) => tys.to_owned().subst(self.tcx(), substs), + ty::TyBool => vec![], + _ => vec![sized_crit.subst(self.tcx(), substs)] + })) } - ty::TyProjection(_) | ty::TyParam(_) => { - // Note: A type parameter is only considered to meet a - // particular bound if there is a where clause telling - // us that it does, and that case is handled by - // `assemble_candidates_from_caller_bounds()`. - Ok(ParameterBuiltin) - } - - ty::TyInfer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - Ok(AmbiguousBuiltin) - } - - ty::TyError => ok_if(Vec::new()), + ty::TyProjection(_) | ty::TyParam(_) => None, + ty::TyInfer(ty::TyVar(_)) => Ambiguous, ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) @@ -1809,27 +1683,60 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } - }; - - fn ok_if<'tcx>(v: Vec>) - -> Result, SelectionError<'tcx>> { - Ok(If(ty::Binder(v))) } + } - fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, - types: Vec>) - -> Result, SelectionError<'tcx>> - { - // First check for markers and other nonsense. - match bound { + fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> + { + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve( + obligation.predicate.skip_binder().self_ty()); + + use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + + match self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(..) | ty::TyError | + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { + Where(ty::Binder(Vec::new())) + } + + ty::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) | + ty::TyClosure(..) | + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { + Never + } + + ty::TyArray(element_ty, _) => { + // (*) binder moved here + Where(ty::Binder(vec![element_ty])) + } + + ty::TyTuple(ref tys) => { + // (*) binder moved here + Where(ty::Binder(tys.clone())) + } + + ty::TyStruct(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) => { // Fallback to whatever user-defined impls exist in this case. - ty::BoundCopy => Ok(ParameterBuiltin), + None + } - // Sized if all the component types are sized. - ty::BoundSized => ok_if(types), + ty::TyInfer(ty::TyVar(_)) => { + // Unbound type variable. Might or might not have + // applicable impls and so forth, depending on what + // those type variables wind up being bound to. + Ambiguous + } - // Shouldn't be coming through here. - ty::BoundSend | ty::BoundSync => bug!(), + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", + self_ty); } } } @@ -1916,20 +1823,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn collect_predicates_for_types(&mut self, - obligation: &TraitObligation<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, trait_def_id: DefId, types: ty::Binder>>) -> Vec> { - let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { - Some(_) => { - self.derived_cause(obligation, BuiltinDerivedObligation) - }, - None => { - self.derived_cause(obligation, ImplDerivedObligation) - } - }; - // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound // regions. For example, `for<'a> Foo<&'a int> : Copy` would @@ -1944,40 +1843,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 2. Produce something like `&'0 int : Copy` // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - // Move the binder into the individual types - let bound_types: Vec>> = - types.skip_binder() - .iter() - .map(|&nested_ty| ty::Binder(nested_ty)) - .collect(); + types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\ + let ty: ty::Binder> = ty::Binder(ty); // <----------/ - // For each type, produce a vector of resulting obligations - let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (skol_ty, skol_map) = - self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); + self.infcx().skolemize_late_bound_regions(&ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = project::normalize_with_depth(self, - obligation.cause.clone(), - obligation.recursion_depth + 1, + cause.clone(), + recursion_depth, &skol_ty); let skol_obligation = util::predicate_for_trait_def(self.tcx(), - derived_cause.clone(), + cause.clone(), trait_def_id, - obligation.recursion_depth + 1, + recursion_depth, normalized_ty, vec![]); obligations.push(skol_obligation); - Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) + self.infcx().plug_leaks(skol_map, snapshot, &obligations) }) - }).collect(); - - // Flatten those vectors (couldn't do it above due `collect`) - match obligations { - Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(), - Err(ErrorReported) => Vec::new(), - } + }).collect() } /////////////////////////////////////////////////////////////////////////// @@ -1997,9 +1884,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate); match candidate { - BuiltinCandidate(builtin_bound) => { + BuiltinCandidate { has_nested } => { Ok(VtableBuiltin( - self.confirm_builtin_candidate(obligation, builtin_bound)?)) + self.confirm_builtin_candidate(obligation, has_nested))) } ParamCandidate(param) => { @@ -2018,9 +1905,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ImplCandidate(impl_def_id) => { - let vtable_impl = - self.confirm_impl_candidate(obligation, impl_def_id)?; - Ok(VtableImpl(vtable_impl)) + Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) } ClosureCandidate(closure_def_id, substs, kind) => { @@ -2064,14 +1949,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - let _: Result<(),()> = - self.infcx.commit_if_ok(|snapshot| { - let result = - self.match_projection_obligation_against_bounds_from_trait(obligation, - snapshot); - assert!(result); - Ok(()) - }); + self.infcx.in_snapshot(|snapshot| { + let result = + self.match_projection_obligation_against_bounds_from_trait(obligation, + snapshot); + assert!(result); + }) } fn confirm_param_candidate(&mut self, @@ -2099,45 +1982,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_candidate(&mut self, obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound) - -> Result>, - SelectionError<'tcx>> + has_nested: bool) + -> VtableBuiltinData> { - debug!("confirm_builtin_candidate({:?})", - obligation); + debug!("confirm_builtin_candidate({:?}, {:?})", + obligation, has_nested); - match self.builtin_bound(bound, obligation)? { - If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), - AmbiguousBuiltin | ParameterBuiltin => { - span_bug!( - obligation.cause.span, - "builtin bound for {:?} was ambig", - obligation); - } - } - } + let obligations = if has_nested { + let trait_def = obligation.predicate.def_id(); + let conditions = match trait_def { + _ if Some(trait_def) == self.tcx().lang_items.sized_trait() => { + self.sized_conditions(obligation) + } + _ if Some(trait_def) == self.tcx().lang_items.copy_trait() => { + self.copy_conditions(obligation) + } + _ => bug!("unexpected builtin trait {:?}", trait_def) + }; + let nested = match conditions { + BuiltinImplConditions::Where(nested) => nested, + _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", + obligation) + }; - fn vtable_builtin_data(&mut self, - obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound, - nested: ty::Binder>>) - -> VtableBuiltinData> - { - debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})", - obligation, bound, nested); - - let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) { - Ok(def_id) => def_id, - Err(_) => { - bug!("builtin trait definition not found"); - } + let cause = self.derived_cause(obligation, BuiltinDerivedObligation); + self.collect_predicates_for_types(cause, + obligation.recursion_depth+1, + trait_def, + nested) + } else { + vec![] }; - let obligations = self.collect_predicates_for_types(obligation, trait_def, nested); - - debug!("vtable_builtin_data: obligations={:?}", + debug!("confirm_builtin_candidate: obligations={:?}", obligations); - VtableBuiltinData { nested: obligations } } @@ -2205,28 +2083,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: ty::Binder>>) -> VtableDefaultImplData> { - debug!("vtable_default_impl_data: nested={:?}", nested); + debug!("vtable_default_impl: nested={:?}", nested); - let mut obligations = self.collect_predicates_for_types(obligation, - trait_def_id, - nested); + let cause = self.derived_cause(obligation, BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + cause, + obligation.recursion_depth+1, + trait_def_id, + nested); - let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { + let trait_obligations = self.infcx.in_snapshot(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - Ok(self.impl_or_trait_obligations(obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_def_id, - &trait_ref.substs, - skol_map, - snapshot)) + let cause = self.derived_cause(obligation, ImplDerivedObligation); + self.impl_or_trait_obligations(cause, + obligation.recursion_depth + 1, + trait_def_id, + &trait_ref.substs, + skol_map, + snapshot) }); - // no Errors in that code above - obligations.append(&mut trait_obligations.unwrap()); + obligations.extend(trait_obligations); - debug!("vtable_default_impl_data: obligations={:?}", obligations); + debug!("vtable_default_impl: obligations={:?}", obligations); VtableDefaultImplData { trait_def_id: trait_def_id, @@ -2237,8 +2118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_impl_candidate(&mut self, obligation: &TraitObligation<'tcx>, impl_def_id: DefId) - -> Result>, - SelectionError<'tcx>> + -> VtableImplData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_impl_candidate({:?},{:?})", obligation, @@ -2246,13 +2126,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (substs, skol_map) = self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate substs={:?}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), - obligation.recursion_depth + 1, skol_map, snapshot)) + let cause = self.derived_cause(obligation, ImplDerivedObligation); + self.vtable_impl(impl_def_id, substs, cause, + obligation.recursion_depth + 1, + skol_map, snapshot) }) } @@ -2507,9 +2389,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let object_did = data.principal_def_id(); - if !object_safety::is_object_safe(tcx, object_did) { - return Err(TraitNotObjectSafe(object_did)); + let mut object_dids = Some(data.principal_def_id()).into_iter(); + // FIXME(#33243) +// data.bounds.builtin_bounds.iter().flat_map(|bound| { +// tcx.lang_items.from_builtin_kind(bound).ok() +// }) +// .chain(Some(data.principal_def_id())); + if let Some(did) = object_dids.find(|did| { + !object_safety::is_object_safe(tcx, *did) + }) { + return Err(TraitNotObjectSafe(did)) } let cause = ObligationCause::new(obligation.cause.span, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 90def00be07..d82f9d7549d 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -18,6 +18,39 @@ use util::nodemap::FnvHashSet; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; +fn anonymize_predicate<'tcx>(tcx: &TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) + -> ty::Predicate<'tcx> { + match *pred { + ty::Predicate::Trait(ref data) => + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Rfc1592(ref data) => + ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))), + + ty::Predicate::Equate(ref data) => + ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::RegionOutlives(ref data) => + ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::TypeOutlives(ref data) => + ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Projection(ref data) => + ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => + ty::Predicate::ObjectSafe(data), + + ty::Predicate::ClosureKind(closure_def_id, kind) => + ty::Predicate::ClosureKind(closure_def_id, kind) + } +} + + struct PredicateSet<'a,'tcx:'a> { tcx: &'a TyCtxt<'tcx>, set: FnvHashSet>, @@ -39,32 +72,7 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { // // to be considered equivalent. So normalize all late-bound // regions before we throw things into the underlying set. - let normalized_pred = match *pred { - ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Equate(ref data) => - ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::RegionOutlives(ref data) => - ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::TypeOutlives(ref data) => - ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Projection(ref data) => - ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data), - - ty::Predicate::ObjectSafe(data) => - ty::Predicate::ObjectSafe(data), - - ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) - }; - self.set.insert(normalized_pred) + self.set.insert(anonymize_predicate(self.tcx, pred)) } } @@ -143,6 +151,9 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { self.stack.extend(predicates); } + ty::Predicate::Rfc1592(..) => { + // Nothing to elaborate. + } ty::Predicate::WellFormed(..) => { // Currently, we do not elaborate WF predicates, // although we easily could. diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 54223e16e17..8fcbc062952 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -329,7 +329,6 @@ impl<'tcx> TyCtxt<'tcx> { where F : FnMut(ty::BoundRegion) -> ty::Region, T : TypeFoldable<'tcx>, { - debug!("replace_late_bound_regions({:?})", value); let mut replacer = RegionReplacer::new(self, &mut f); let result = value.skip_binder().fold_with(&mut replacer); (result, replacer.map) @@ -444,8 +443,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { - debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})", - r, self.current_depth); let fld_r = &mut self.fld_r; let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); if let ty::ReLateBound(debruijn1, br) = region { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bc342b235dd..3e3dae3b3e9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -804,6 +804,9 @@ pub enum Predicate<'tcx> { /// would be the parameters in the `TypeSpace`. Trait(PolyTraitPredicate<'tcx>), + /// A predicate created by RFC1592 + Rfc1592(Box>), + /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -904,6 +907,8 @@ impl<'tcx> Predicate<'tcx> { match *self { Predicate::Trait(ty::Binder(ref data)) => Predicate::Trait(ty::Binder(data.subst(tcx, substs))), + Predicate::Rfc1592(ref pi) => + Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => @@ -1083,6 +1088,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Trait(ref data) => { data.0.trait_ref.substs.types.as_slice().to_vec() } + ty::Predicate::Rfc1592(ref data) => { + return data.walk_tys() + } ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } @@ -1123,6 +1131,7 @@ impl<'tcx> Predicate<'tcx> { Predicate::Trait(ref t) => { Some(t.to_poly_trait_ref()) } + Predicate::Rfc1592(..) | Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | @@ -1498,6 +1507,7 @@ pub struct AdtDefData<'tcx, 'container: 'tcx> { pub variants: Vec>, destructor: Cell>, flags: Cell, + sized_constraint: ivar::TyIVar<'tcx, 'container>, } impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { @@ -1575,7 +1585,8 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { did: did, variants: variants, flags: Cell::new(flags), - destructor: Cell::new(None) + destructor: Cell::new(None), + sized_constraint: ivar::TyIVar::new(), } } @@ -1716,6 +1727,185 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { None => NoDtor, } } + + /// Returns a simpler type such that `Self: Sized` if and only + /// if that type is Sized, or `TyErr` if this type is recursive. + /// + /// HACK: instead of returning a list of types, this function can + /// return a tuple. In that case, the result is Sized only if + /// all elements of the tuple are Sized. + /// + /// This is generally the `struct_tail` if this is a struct, or a + /// tuple of them if this is an enum. + /// + /// Oddly enough, checking that the sized-constraint is Sized is + /// actually more expressive than checking all members: + /// the Sized trait is inductive, so an associated type that references + /// Self would prevent its containing ADT from being Sized. + /// + /// Due to normalization being eager, this applies even if + /// the associated type is behind a pointer, e.g. issue #31299. + pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> { + let dep_node = DepNode::SizedConstraint(self.did); + match self.sized_constraint.get(dep_node) { + None => { + let this = tcx.lookup_adt_def_master(self.did); + this.calculate_sized_constraint_inner(tcx, &mut Vec::new()); + self.sized_constraint(tcx) + } + Some(ty) => ty + } + } +} + +impl<'tcx> AdtDefData<'tcx, 'tcx> { + /// Calculates the Sized-constraint. + /// + /// As the Sized-constraint of enums can be a *set* of types, + /// the Sized-constraint may need to be a set also. Because introducing + /// a new type of IVar is currently a complex affair, the Sized-constraint + /// may be a tuple. + /// + /// In fact, there are only a few options for the constraint: + /// - `bool`, if the type is always Sized + /// - an obviously-unsized type + /// - a type parameter or projection whose Sizedness can't be known + /// - a tuple of type parameters or projections, if there are multiple + /// such. + /// - a TyError, if a type contained itself. The representability + /// check should catch this case. + fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>) + { + + let dep_node = DepNode::SizedConstraint(self.did); + + if self.sized_constraint.get(dep_node).is_some() { + return; + } + + if stack.contains(&self) { + debug!("calculate_sized_constraint: {:?} is recursive", self); + // This should be reported as an error by `check_representable`. + // + // Consider the type as Sized in the meanwhile to avoid + // further errors. + self.sized_constraint.fulfill(dep_node, tcx.types.err); + return; + } + + stack.push(self); + + let tys : Vec<_> = + self.variants.iter().flat_map(|v| { + v.fields.last() + }).flat_map(|f| { + self.sized_constraint_for_ty(tcx, stack, f.unsubst_ty()) + }).collect(); + + let self_ = stack.pop().unwrap(); + assert_eq!(self_, self); + + let ty = match tys.len() { + _ if tys.references_error() => tcx.types.err, + 0 => tcx.types.bool, + 1 => tys[0], + _ => tcx.mk_tup(tys) + }; + + match self.sized_constraint.get(dep_node) { + Some(old_ty) => { + debug!("calculate_sized_constraint: {:?} recurred", self); + assert_eq!(old_ty, tcx.types.err) + } + None => { + debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); + self.sized_constraint.fulfill(dep_node, ty) + } + } + } + + fn sized_constraint_for_ty( + &'tcx self, + tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>, + ty: Ty<'tcx> + ) -> Vec> { + let result = match ty.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyArray(..) | TyClosure(..) => { + vec![] + } + + TyStr | TyTrait(..) | TySlice(_) | TyError => { + // these are never sized - return the target type + vec![ty] + } + + TyTuple(ref tys) => { + // FIXME(#33242) we only need to constrain the last field + tys.iter().flat_map(|ty| { + self.sized_constraint_for_ty(tcx, stack, ty) + }).collect() + } + + TyEnum(adt, substs) | TyStruct(adt, substs) => { + // recursive case + let adt = tcx.lookup_adt_def_master(adt.did); + adt.calculate_sized_constraint_inner(tcx, stack); + let adt_ty = + adt.sized_constraint + .unwrap(DepNode::SizedConstraint(adt.did)) + .subst(tcx, substs); + debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", + ty, adt_ty); + if let ty::TyTuple(ref tys) = adt_ty.sty { + tys.iter().flat_map(|ty| { + self.sized_constraint_for_ty(tcx, stack, ty) + }).collect() + } else { + self.sized_constraint_for_ty(tcx, stack, adt_ty) + } + } + + TyProjection(..) => { + // must calculate explicitly. + // FIXME: consider special-casing always-Sized projections + vec![ty] + } + + TyParam(..) => { + // perf hack: if there is a `T: Sized` bound, then + // we know that `T` is Sized and do not need to check + // it on the impl. + + let sized_trait = match tcx.lang_items.sized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + let sized_predicate = Binder(TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs(Substs::new_trait( + vec![], vec![], ty + )) + }).to_predicate(); + let predicates = tcx.lookup_predicates(self.did).predicates; + if predicates.into_iter().any(|p| p == sized_predicate) { + vec![] + } else { + vec![ty] + } + } + + TyInfer(..) => { + bug!("unexpected type `{:?}` in sized_constraint_for_ty", + ty) + } + }; + debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); + result + } } impl<'tcx, 'container> VariantDefData<'tcx, 'container> { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4d64dd83071..ac3dfa82bd6 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -634,6 +634,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), + ty::Predicate::Rfc1592(ref a) => + ty::Predicate::Rfc1592(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => @@ -654,6 +656,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), + ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2e4f37f1cc1..b6bd8f5f55f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -299,6 +299,7 @@ impl<'tcx> TyCtxt<'tcx> { match predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f93332e0773..609252f948a 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,9 @@ pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Rfc1592(ref data) => { + bug!("RFC1592 predicate `{:?}` in predicate_obligations", data); + } } wf.normalize() @@ -155,6 +158,7 @@ pub fn implied_bounds<'a,'tcx>( assert!(!obligation.has_escaping_regions()); match obligation.predicate { ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | @@ -280,11 +284,35 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { } } + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>, + rfc1592: bool) { + if !subty.has_escaping_regions() { + let cause = self.cause(cause); + match traits::trait_ref_for_builtin_bound(self.infcx.tcx, + ty::BoundSized, + subty) { + Ok(trait_ref) => { + let predicate = trait_ref.to_predicate(); + let predicate = if rfc1592 { + ty::Predicate::Rfc1592(box predicate) + } else { + predicate + }; + self.out.push( + traits::Obligation::new(cause, + predicate)); + } + Err(ErrorReported) => { } + } + } + } + /// Push new obligations into `out`. Returns true if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { + let tcx = self.infcx.tcx; let mut subtys = ty0.walk(); while let Some(ty) = subtys.next() { match ty.sty { @@ -301,23 +329,18 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { ty::TySlice(subty) | ty::TyArray(subty, _) => { - if !subty.has_escaping_regions() { - let cause = self.cause(traits::SliceOrArrayElem); - match traits::trait_ref_for_builtin_bound(self.infcx.tcx, - ty::BoundSized, - subty) { - Ok(trait_ref) => { - self.out.push( - traits::Obligation::new(cause, - trait_ref.to_predicate())); - } - Err(ErrorReported) => { } + self.require_sized(subty, traits::SliceOrArrayElem, false); + } + + ty::TyTuple(ref tys) => { + if let Some((_last, rest)) = tys.split_last() { + for elem in rest { + self.require_sized(elem, traits::TupleElem, true); } } } ty::TyBox(_) | - ty::TyTuple(_) | ty::TyRawPtr(_) => { // simple cases that are WF if their type args are WF } @@ -374,10 +397,25 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { // checking those let cause = self.cause(traits::MiscObligation); - self.out.push( - traits::Obligation::new( - cause, - ty::Predicate::ObjectSafe(data.principal_def_id()))); + + // FIXME(#33243): remove RFC1592 + self.out.push(traits::Obligation::new( + cause.clone(), + ty::Predicate::ObjectSafe(data.principal_def_id()) + )); + let component_traits = + data.bounds.builtin_bounds.iter().flat_map(|bound| { + tcx.lang_items.from_builtin_kind(bound).ok() + }); +// .chain(Some(data.principal_def_id())); + self.out.extend( + component_traits.map(|did| { traits::Obligation::new( + cause.clone(), + ty::Predicate::Rfc1592( + box ty::Predicate::ObjectSafe(did) + ) + )}) + ); } // Inference variables are the complicated case, since we don't diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9b590ec8aa6..728306b25dd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -459,6 +459,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), + ty::Predicate::Rfc1592(ref a) => { + write!(f, "RFC1592({:?})", a) + } ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), @@ -493,7 +496,7 @@ impl fmt::Debug for ty::BoundRegion { BrAnon(n) => write!(f, "BrAnon({:?})", n), BrFresh(n) => write!(f, "BrFresh({:?})", n), BrNamed(did, name) => { - write!(f, "BrNamed({:?}, {:?})", did, name) + write!(f, "BrNamed({:?}:{:?}, {:?})", did.krate, did.index, name) } BrEnv => "BrEnv".fmt(f), } @@ -1056,6 +1059,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), + ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index ba8107e03c9..26f512e0613 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -42,7 +42,7 @@ fn read_u32v_be(dst: &mut[u32], input: &[u8]) { } } -trait ToBits { +trait ToBits: Sized { /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the /// high-order value and the 2nd item is the low order value. fn to_bits(self) -> (Self, Self); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e7c9097a56a..e0abe1aebd2 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -190,6 +190,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), reference: "RFC 1445 ", }, + FutureIncompatibleInfo { + id: LintId::of(UNSIZED_IN_TUPLE), + reference: "issue #33242 ", + }, + FutureIncompatibleInfo { + id: LintId::of(OBJECT_UNSAFE_FRAGMENT), + reference: "issue #33243 ", + } ]); // We have one lint pass defined specially diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 61d055d4d51..57aa347847e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -449,6 +449,9 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, p: &ty::Predicate<'tcx>) { match *p { + ty::Predicate::Rfc1592(..) => { + bug!("RFC1592 predicate in metadata `{:?}`", p); + } ty::Predicate::Trait(ref trait_ref) => { write!(w, "t"); enc_trait_ref(w, cx, trait_ref.0.trait_ref); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index dede4d2a42a..6fb9739fca4 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -277,6 +277,9 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { traits::report_fulfillment_errors(&infcx, errors); } } + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { + traits::report_fulfillment_errors_as_warnings(&infcx, errors, e.id); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ac7745985e6..5e07011d5ba 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1143,8 +1143,8 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, traits::astconv_object_safety_violations(tcx, principal.def_id()); if !object_safety_violations.is_empty() { traits::report_object_safety_error( - tcx, span, principal.def_id(), object_safety_violations) - .emit(); + tcx, span, principal.def_id(), None, object_safety_violations) + .unwrap().emit(); return tcx.types.err; } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4ac7e3323ef..b84ded1ea7a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -179,6 +179,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::Rfc1592(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f1c6868efd2..6c8d437f429 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -477,7 +477,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - report_selection_error(self.fcx.infcx(), &obligation, &err); + report_selection_error(self.fcx.infcx(), &obligation, &err, None); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 368b826b1bb..b9fda210454 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -114,6 +114,11 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( return Err(()); } + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { + traits::report_fulfillment_errors_as_warnings(&infcx, errors, + drop_impl_node_id); + } + let free_regions = FreeRegionMap::new(); infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); Ok(()) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2defbf0d33e..8a71debdf20 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -492,6 +492,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::TypeOutlives(..) => { None } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 385f04b8564..6599199c239 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1989,13 +1989,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // upvar inference should have ensured that all deferred call // resolutions are handled by now. assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); + let infcx = self.infcx(); self.select_all_obligations_and_apply_defaults(); let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - match fulfillment_cx.select_all_or_error(self.infcx()) { + match fulfillment_cx.select_all_or_error(infcx) { Ok(()) => { } - Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + Err(errors) => { report_fulfillment_errors(infcx, &errors); } + } + + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(infcx) { + traits::report_fulfillment_errors_as_warnings(infcx, errors, self.body_id); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c10488a03ef..4dd093e2e4b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -450,6 +450,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { ty::Predicate::TypeOutlives(ref data) => { data.skip_binder().0.is_param(def.space, def.index) } + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0a606e1425c..398781e1405 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -866,6 +866,7 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), + Predicate::Rfc1592(..) => panic!("not user writable"), } } } diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs index edbc8c82432..f39fb0e31c6 100644 --- a/src/test/compile-fail/issue-17431-2.rs +++ b/src/test/compile-fail/issue-17431-2.rs @@ -9,6 +9,7 @@ // except according to those terms. struct Baz { q: Option } +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option } //~^ ERROR recursive type `Foo` has infinite size diff --git a/src/test/compile-fail/issue-20692.rs b/src/test/compile-fail/issue-20692.rs index 62d775adac3..1c9e588cb2c 100644 --- a/src/test/compile-fail/issue-20692.rs +++ b/src/test/compile-fail/issue-20692.rs @@ -14,6 +14,7 @@ fn f(x: &T) { let _ = x //~^ ERROR `Array` cannot be made into an object //~| NOTE the trait cannot require that `Self : Sized` + //~| NOTE requirements on the impl of `std::ops::CoerceUnsized<&Array>` as &Array; //~^ ERROR `Array` cannot be made into an object diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 28080ae09e5..2919b0b3cac 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: overflow representing the type `S` + trait Mirror { type It: ?Sized; } impl Mirror for T { type It = Self; } struct S(Option<::It>); -//~^ ERROR recursive type `S` has infinite size fn main() { let _s = S(None); diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs new file mode 100644 index 00000000000..c4e8f766117 --- /dev/null +++ b/src/test/compile-fail/issue-32963.rs @@ -0,0 +1,20 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +trait Misc {} + +fn size_of_copy() -> usize { mem::size_of::() } + +fn main() { + size_of_copy::(); + //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied +} diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 08b4e1a45f3..747fe2d2046 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -45,15 +45,15 @@ fn test<'a,T,U:Copy>(_: &'a isize) { // borrowed object types are generally ok assert_copy::<&'a Dummy>(); - assert_copy::<&'a (Dummy+Copy)>(); - assert_copy::<&'static (Dummy+Copy)>(); + assert_copy::<&'a (Dummy+Send)>(); + assert_copy::<&'static (Dummy+Send)>(); // owned object types are not ok assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied // mutable object types are not ok - assert_copy::<&'a mut (Dummy+Copy)>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'a mut (Dummy+Send)>(); //~ ERROR : std::marker::Copy` is not satisfied // unsafe ptrs are ok assert_copy::<*const isize>(); diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 895d2450cfe..2a0773af73b 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,4 @@ pub fn main() { let arr: &[_] = &[1, 2, 3]; let range = *arr..; //~^ ERROR `[_]: std::marker::Sized` is not satisfied - //~| ERROR `[_]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs new file mode 100644 index 00000000000..e766f977200 --- /dev/null +++ b/src/test/compile-fail/rfc1592-deprecated.rs @@ -0,0 +1,32 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); } +//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied +//~| WARNING hard error + +impl Foo for T { + fn foo(&self) -> (Self, Self) { + (*self, *self) + } +} + +#[deny(warnings)] +fn main() { + assert_eq!((11).foo(), (11, 11)); + + let junk: Box = Box::new(42); + //~^ ERROR the trait cannot require that `Self : Sized` + //~| WARNING hard error + let f = format!("{:?}", junk); + assert_eq!(f, "42"); +} diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs index 3d7c4868e96..712b4ac22f0 100644 --- a/src/test/compile-fail/sized-cycle-note.rs +++ b/src/test/compile-fail/sized-cycle-note.rs @@ -17,14 +17,9 @@ // 2. it should elaborate the steps that led to the cycle. struct Baz { q: Option } - +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option } //~^ ERROR recursive type `Foo` has infinite size -//~| NOTE type `Foo` is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `Baz`... -//~| NOTE ...which in turn is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle. impl Foo { fn bar(&self) {} } diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 663cb0a1716..d40c12f67a0 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,9 +14,9 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); // same + let _: (isize, (X, isize)); let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied + let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs new file mode 100644 index 00000000000..6c04e66068e --- /dev/null +++ b/src/test/run-pass/issue-31299.rs @@ -0,0 +1,43 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #31299. This was generating an overflow error +// because of eager normalization: +// +// proving `M: Sized` requires +// - proving `PtrBack>: Sized` requires +// - normalizing `Vec< as Front>::Back>>: Sized` requires +// - proving `Vec: Front` requires +// - `M: Sized` <-- cycle! +// +// If we skip the normalization step, though, everything goes fine. +// +// This could be fixed by implementing lazy normalization everywhere. +// +// However, we want this to work before then. For that, when checking +// whether a type is Sized we only check that the tails are Sized. As +// PtrBack does not have a tail, we don't need to normalize anything +// and this compiles + +trait Front { + type Back; +} + +impl Front for Vec { + type Back = Vec; +} + +struct PtrBack(Vec); + +struct M(PtrBack>); + +fn main() { + std::mem::size_of::(); +} diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs new file mode 100644 index 00000000000..81bf0258789 --- /dev/null +++ b/src/test/run-pass/rfc1592-deprecated.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +trait Foo { + fn foo(&self) -> (Self, Self); +} + +impl Foo for T { + fn foo(&self) -> (Self, Self) { + (*self, *self) + } +} + +fn main() { + assert_eq!((11).foo(), (11, 11)); + + let junk: Box = Box::new(42); + let f = format!("{:?}", junk); + assert_eq!(f, "42"); +}