Auto merge of #33138 - arielb1:sized-shortcut, r=nikomatsakis
Short-cut `T: Sized` trait selection for ADTs Basically avoids all nested obligations when checking whether an ADT is sized - this speeds up typeck by ~15% The refactoring fixed #32963, but I also want to make `Copy` not object-safe (will commit that soon). Fixes #33201 r? @nikomatsakis
This commit is contained in:
commit
5158f3b282
|
@ -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);
|
||||
|
|
|
@ -88,6 +88,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
ImplOrTraitItems(D),
|
||||
ItemSignature(D),
|
||||
FieldTy(D),
|
||||
SizedConstraint(D),
|
||||
TraitItemDefIds(D),
|
||||
InherentImpls(D),
|
||||
ImplItems(D),
|
||||
|
@ -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),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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<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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,13 +64,23 @@ impl<'tcx> TraitErrorKey<'tcx> {
|
|||
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) {
|
||||
|
@ -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,12 +102,22 @@ 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() {
|
||||
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,
|
||||
|
@ -102,6 +126,7 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_unimplemented_note<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
@ -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 => {
|
||||
|
@ -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,13 +517,16 @@ 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,
|
||||
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) => {
|
||||
let found_kind = infcx.closure_kind(closure_def_id).unwrap();
|
||||
|
@ -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,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,
|
||||
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!(
|
||||
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));
|
||||
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));
|
||||
|
|
|
@ -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<PendingPredicateObligation<'tcx>,
|
||||
LocalFulfilledPredicates<'tcx>>,
|
||||
|
||||
// A list of new obligations due to RFC1592.
|
||||
rfc1592_obligations: Vec<PredicateObligation<'tcx>>,
|
||||
|
||||
// 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<FulfillmentError<'tcx>>>
|
||||
{
|
||||
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<FulfillmentError<'tcx>>>
|
||||
{
|
||||
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))
|
||||
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<PendingPredicateObligation<'tcx>>,
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
|
||||
rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>)
|
||||
-> Result<Option<Vec<PendingPredicateObligation<'tcx>>>,
|
||||
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<Vec<RegionObligation<'tcx>>>)
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
|
||||
rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>)
|
||||
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
|
||||
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![]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>),
|
||||
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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<Vec<Ty<'tcx>>>),
|
||||
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<Vec<Ty<'tcx>>>),
|
||||
/// 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<BuiltinBoundConditions<'tcx>,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<T>
|
||||
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<Ty> = 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<Ty<'tcx>>)
|
||||
-> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>> {
|
||||
Ok(If(ty::Binder(v)))
|
||||
}
|
||||
}
|
||||
|
||||
fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
|
||||
types: Vec<Ty<'tcx>>)
|
||||
-> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>>
|
||||
fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
|
||||
-> BuiltinImplConditions<'tcx>
|
||||
{
|
||||
// First check for markers and other nonsense.
|
||||
match bound {
|
||||
// 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<Ty<'tcx>>>)
|
||||
-> Vec<PredicateObligation<'tcx>>
|
||||
{
|
||||
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<ty::Binder<Ty<'tcx>>> =
|
||||
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<'tcx>> = ty::Binder(ty); // <----------/
|
||||
|
||||
// For each type, produce a vector of resulting obligations
|
||||
let obligations: Result<Vec<Vec<_>>, _> = 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| {
|
||||
self.infcx.in_snapshot(|snapshot| {
|
||||
let result =
|
||||
self.match_projection_obligation_against_bounds_from_trait(obligation,
|
||||
snapshot);
|
||||
assert!(result);
|
||||
Ok(())
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
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<VtableBuiltinData<PredicateObligation<'tcx>>,
|
||||
SelectionError<'tcx>>
|
||||
{
|
||||
debug!("confirm_builtin_candidate({:?})",
|
||||
obligation);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn vtable_builtin_data(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
nested: ty::Binder<Vec<Ty<'tcx>>>)
|
||||
has_nested: bool)
|
||||
-> VtableBuiltinData<PredicateObligation<'tcx>>
|
||||
{
|
||||
debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})",
|
||||
obligation, bound, nested);
|
||||
debug!("confirm_builtin_candidate({:?}, {:?})",
|
||||
obligation, has_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 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)
|
||||
};
|
||||
|
||||
let obligations = self.collect_predicates_for_types(obligation, trait_def, nested);
|
||||
let cause = self.derived_cause(obligation, BuiltinDerivedObligation);
|
||||
self.collect_predicates_for_types(cause,
|
||||
obligation.recursion_depth+1,
|
||||
trait_def,
|
||||
nested)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
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<Vec<Ty<'tcx>>>)
|
||||
-> VtableDefaultImplData<PredicateObligation<'tcx>>
|
||||
{
|
||||
debug!("vtable_default_impl_data: nested={:?}", nested);
|
||||
debug!("vtable_default_impl: nested={:?}", nested);
|
||||
|
||||
let mut obligations = self.collect_predicates_for_types(obligation,
|
||||
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<Vec<_>,()> = 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(),
|
||||
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))
|
||||
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<VtableImplData<'tcx, PredicateObligation<'tcx>>,
|
||||
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,
|
||||
|
|
|
@ -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<ty::Predicate<'tcx>>,
|
||||
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Predicate<'tcx>>),
|
||||
|
||||
/// 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<VariantDefData<'tcx, 'container>>,
|
||||
destructor: Cell<Option<DefId>>,
|
||||
flags: Cell<AdtFlags>,
|
||||
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<AdtDefMaster<'tcx>>)
|
||||
{
|
||||
|
||||
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<AdtDefMaster<'tcx>>,
|
||||
ty: Ty<'tcx>
|
||||
) -> Vec<Ty<'tcx>> {
|
||||
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> {
|
||||
|
|
|
@ -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<V: TypeVisitor<'tcx>>(&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),
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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()));
|
||||
self.require_sized(subty, traits::SliceOrArrayElem, false);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
|
||||
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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <https://github.com/rust-lang/rfcs/pull/1445>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(UNSIZED_IN_TUPLE),
|
||||
reference: "issue #33242 <https://github.com/rust-lang/rust/issues/33242>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
|
||||
reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
|
||||
}
|
||||
]);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
|
|
|
@ -449,6 +449,9 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
|
|||
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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -866,6 +866,7 @@ impl<'a> Clean<WherePredicate> 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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
struct Baz { q: Option<Foo> }
|
||||
//~^ ERROR recursive type `Baz` has infinite size
|
||||
|
||||
struct Foo { q: Option<Baz> }
|
||||
//~^ ERROR recursive type `Foo` has infinite size
|
||||
|
|
|
@ -14,6 +14,7 @@ fn f<T: Array>(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
|
||||
|
|
|
@ -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<T: ?Sized> Mirror for T { type It = Self; }
|
||||
struct S(Option<<S as Mirror>::It>);
|
||||
//~^ ERROR recursive type `S` has infinite size
|
||||
|
||||
fn main() {
|
||||
let _s = S(None);
|
||||
|
|
|
@ -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 <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::mem;
|
||||
|
||||
trait Misc {}
|
||||
|
||||
fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
|
||||
|
||||
fn main() {
|
||||
size_of_copy::<Misc+Copy>();
|
||||
//~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied
|
||||
}
|
|
@ -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::<Box<Dummy>>(); //~ ERROR : std::marker::Copy` is not satisfied
|
||||
assert_copy::<Box<Dummy+Copy>>(); //~ ERROR : std::marker::Copy` is not satisfied
|
||||
assert_copy::<Box<Dummy+Send>>(); //~ 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>();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 <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::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<T: Copy> Foo for T {
|
||||
fn foo(&self) -> (Self, Self) {
|
||||
(*self, *self)
|
||||
}
|
||||
}
|
||||
|
||||
#[deny(warnings)]
|
||||
fn main() {
|
||||
assert_eq!((11).foo(), (11, 11));
|
||||
|
||||
let junk: Box<fmt::Debug+Sized> = Box::new(42);
|
||||
//~^ ERROR the trait cannot require that `Self : Sized`
|
||||
//~| WARNING hard error
|
||||
let f = format!("{:?}", junk);
|
||||
assert_eq!(f, "42");
|
||||
}
|
|
@ -17,14 +17,9 @@
|
|||
// 2. it should elaborate the steps that led to the cycle.
|
||||
|
||||
struct Baz { q: Option<Foo> }
|
||||
|
||||
//~^ ERROR recursive type `Baz` has infinite size
|
||||
struct Foo { q: Option<Baz> }
|
||||
//~^ ERROR recursive type `Foo` has infinite size
|
||||
//~| NOTE type `Foo` is embedded within `std::option::Option<Foo>`...
|
||||
//~| NOTE ...which in turn is embedded within `std::option::Option<Foo>`...
|
||||
//~| NOTE ...which in turn is embedded within `Baz`...
|
||||
//~| NOTE ...which in turn is embedded within `std::option::Option<Baz>`...
|
||||
//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle.
|
||||
|
||||
impl Foo { fn bar(&self) {} }
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@ trait T {}
|
|||
|
||||
fn f1<X: ?Sized>(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: ?Sized + T>(x: &X) {
|
||||
let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
|
||||
|
|
|
@ -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 <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.
|
||||
|
||||
// Regression test for #31299. This was generating an overflow error
|
||||
// because of eager normalization:
|
||||
//
|
||||
// proving `M: Sized` requires
|
||||
// - proving `PtrBack<Vec<M>>: Sized` requires
|
||||
// - normalizing `Vec<<Vec<M> as Front>::Back>>: Sized` requires
|
||||
// - proving `Vec<M>: 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<T> Front for Vec<T> {
|
||||
type Back = Vec<T>;
|
||||
}
|
||||
|
||||
struct PtrBack<T: Front>(Vec<T::Back>);
|
||||
|
||||
struct M(PtrBack<Vec<M>>);
|
||||
|
||||
fn main() {
|
||||
std::mem::size_of::<M>();
|
||||
}
|
|
@ -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 <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::fmt;
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self) -> (Self, Self);
|
||||
}
|
||||
|
||||
impl<T: Copy> Foo for T {
|
||||
fn foo(&self) -> (Self, Self) {
|
||||
(*self, *self)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!((11).foo(), (11, 11));
|
||||
|
||||
let junk: Box<fmt::Debug+Sized> = Box::new(42);
|
||||
let f = format!("{:?}", junk);
|
||||
assert_eq!(f, "42");
|
||||
}
|
Loading…
Reference in New Issue