Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5158f3b

Browse files
committedMay 6, 2016
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
2 parents a36c419 + 238e4ee commit 5158f3b

40 files changed

+845
-413
lines changed
 

‎src/libcore/num/bignum.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use mem;
3333
use intrinsics;
3434

3535
/// Arithmetic operations required by bignums.
36-
pub trait FullOps {
36+
pub trait FullOps: Sized {
3737
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
3838
/// where `W` is the number of bits in `Self`.
3939
fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);

‎src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub enum DepNode<D: Clone + Debug> {
8888
ImplOrTraitItems(D),
8989
ItemSignature(D),
9090
FieldTy(D),
91+
SizedConstraint(D),
9192
TraitItemDefIds(D),
9293
InherentImpls(D),
9394
ImplItems(D),
@@ -193,6 +194,7 @@ impl<D: Clone + Debug> DepNode<D> {
193194
ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
194195
ItemSignature(ref d) => op(d).map(ItemSignature),
195196
FieldTy(ref d) => op(d).map(FieldTy),
197+
SizedConstraint(ref d) => op(d).map(SizedConstraint),
196198
TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
197199
InherentImpls(ref d) => op(d).map(InherentImpls),
198200
ImplItems(ref d) => op(d).map(ImplItems),

‎src/librustc/infer/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
814814
r
815815
}
816816

817+
// Execute `f` in a snapshot, and commit the bindings it creates
818+
pub fn in_snapshot<T, F>(&self, f: F) -> T where
819+
F: FnOnce(&CombinedSnapshot) -> T
820+
{
821+
debug!("in_snapshot()");
822+
let snapshot = self.start_snapshot();
823+
let r = f(&snapshot);
824+
self.commit_from(snapshot);
825+
r
826+
}
827+
817828
/// Execute `f` and commit only the region bindings if successful.
818829
/// The function f must be very careful not to leak any non-region
819830
/// variables that get created.

‎src/librustc/lint/builtin.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ declare_lint! {
185185
"detects super or self keywords at the beginning of global path"
186186
}
187187

188+
declare_lint! {
189+
pub UNSIZED_IN_TUPLE,
190+
Warn,
191+
"unsized types in the interior of a tuple were erroneously allowed"
192+
}
193+
194+
declare_lint! {
195+
pub OBJECT_UNSAFE_FRAGMENT,
196+
Warn,
197+
"object-unsafe non-principal fragments in object types were erroneously allowed"
198+
}
199+
188200
/// Does nothing as a lint pass, but registers some `Lint`s
189201
/// which are used by other parts of the compiler.
190202
#[derive(Copy, Clone)]
@@ -220,7 +232,9 @@ impl LintPass for HardwiredLints {
220232
TRANSMUTE_FROM_FN_ITEM_TYPES,
221233
OVERLAPPING_INHERENT_IMPLS,
222234
RENAMED_AND_REMOVED_LINTS,
223-
SUPER_OR_SELF_IN_GLOBAL_PATH
235+
SUPER_OR_SELF_IN_GLOBAL_PATH,
236+
UNSIZED_IN_TUPLE,
237+
OBJECT_UNSAFE_FRAGMENT
224238
)
225239
}
226240
}

‎src/librustc/middle/free_region.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl FreeRegionMap {
5656
match *predicate {
5757
ty::Predicate::Projection(..) |
5858
ty::Predicate::Trait(..) |
59+
ty::Predicate::Rfc1592(..) |
5960
ty::Predicate::Equate(..) |
6061
ty::Predicate::WellFormed(..) |
6162
ty::Predicate::ObjectSafe(..) |

‎src/librustc/traits/error_reporting.rs

+116-40
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,51 @@ use util::nodemap::{FnvHashMap, FnvHashSet};
3636
use std::cmp;
3737
use std::fmt;
3838
use syntax::attr::{AttributeMethods, AttrMetaMethods};
39+
use syntax::ast;
3940
use syntax::codemap::Span;
4041
use syntax::errors::DiagnosticBuilder;
4142

4243
#[derive(Debug, PartialEq, Eq, Hash)]
4344
pub struct TraitErrorKey<'tcx> {
4445
span: Span,
46+
warning_node_id: Option<ast::NodeId>,
4547
predicate: ty::Predicate<'tcx>
4648
}
4749

4850
impl<'tcx> TraitErrorKey<'tcx> {
4951
fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
50-
e: &FulfillmentError<'tcx>) -> Self {
52+
e: &FulfillmentError<'tcx>,
53+
warning_node_id: Option<ast::NodeId>) -> Self {
5154
let predicate =
5255
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
5356
TraitErrorKey {
5457
span: e.obligation.cause.span,
55-
predicate: infcx.tcx.erase_regions(&predicate)
58+
predicate: infcx.tcx.erase_regions(&predicate),
59+
warning_node_id: warning_node_id
5660
}
5761
}
5862
}
5963

6064
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
6165
errors: &Vec<FulfillmentError<'tcx>>) {
6266
for error in errors {
63-
report_fulfillment_error(infcx, error);
67+
report_fulfillment_error(infcx, error, None);
68+
}
69+
}
70+
71+
pub fn report_fulfillment_errors_as_warnings<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
72+
errors: &Vec<FulfillmentError<'tcx>>,
73+
node_id: ast::NodeId)
74+
{
75+
for error in errors {
76+
report_fulfillment_error(infcx, error, Some(node_id));
6477
}
6578
}
6679

6780
fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
68-
error: &FulfillmentError<'tcx>) {
69-
let error_key = TraitErrorKey::from_error(infcx, error);
81+
error: &FulfillmentError<'tcx>,
82+
warning_node_id: Option<ast::NodeId>) {
83+
let error_key = TraitErrorKey::from_error(infcx, error, warning_node_id);
7084
debug!("report_fulfillment_errors({:?}) - key={:?}",
7185
error, error_key);
7286
if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
@@ -75,10 +89,10 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
7589
}
7690
match error.code {
7791
FulfillmentErrorCode::CodeSelectionError(ref e) => {
78-
report_selection_error(infcx, &error.obligation, e);
92+
report_selection_error(infcx, &error.obligation, e, warning_node_id);
7993
}
8094
FulfillmentErrorCode::CodeProjectionError(ref e) => {
81-
report_projection_error(infcx, &error.obligation, e);
95+
report_projection_error(infcx, &error.obligation, e, warning_node_id);
8296
}
8397
FulfillmentErrorCode::CodeAmbiguity => {
8498
maybe_report_ambiguity(infcx, &error.obligation);
@@ -88,18 +102,29 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
88102

89103
pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
90104
obligation: &PredicateObligation<'tcx>,
91-
error: &MismatchedProjectionTypes<'tcx>)
105+
error: &MismatchedProjectionTypes<'tcx>,
106+
warning_node_id: Option<ast::NodeId>)
92107
{
93108
let predicate =
94109
infcx.resolve_type_vars_if_possible(&obligation.predicate);
95110

96111
if !predicate.references_error() {
97-
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
98-
"type mismatch resolving `{}`: {}",
99-
predicate,
100-
error.err);
101-
note_obligation_cause(infcx, &mut err, obligation);
102-
err.emit();
112+
if let Some(warning_node_id) = warning_node_id {
113+
infcx.tcx.sess.add_lint(
114+
::lint::builtin::UNSIZED_IN_TUPLE,
115+
warning_node_id,
116+
obligation.cause.span,
117+
format!("type mismatch resolving `{}`: {}",
118+
predicate,
119+
error.err));
120+
} else {
121+
let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
122+
"type mismatch resolving `{}`: {}",
123+
predicate,
124+
error.err);
125+
note_obligation_cause(infcx, &mut err, obligation);
126+
err.emit();
127+
}
103128
}
104129
}
105130

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

384409
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
385410
obligation: &PredicateObligation<'tcx>,
386-
error: &SelectionError<'tcx>)
411+
error: &SelectionError<'tcx>,
412+
warning_node_id: Option<ast::NodeId>)
387413
{
388414
match *error {
389415
SelectionError::Unimplemented => {
@@ -401,6 +427,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
401427

402428
if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() {
403429
let trait_ref = trait_predicate.to_poly_trait_ref();
430+
431+
if let Some(warning_node_id) = warning_node_id {
432+
infcx.tcx.sess.add_lint(
433+
::lint::builtin::UNSIZED_IN_TUPLE,
434+
warning_node_id,
435+
obligation.cause.span,
436+
format!("the trait bound `{}` is not satisfied",
437+
trait_ref.to_predicate()));
438+
return;
439+
}
440+
404441
let mut err = struct_span_err!(
405442
infcx.tcx.sess, obligation.cause.span, E0277,
406443
"the trait bound `{}` is not satisfied",
@@ -480,12 +517,15 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
480517
ty::Predicate::ObjectSafe(trait_def_id) => {
481518
let violations = object_safety_violations(
482519
infcx.tcx, trait_def_id);
483-
let mut err = report_object_safety_error(infcx.tcx,
484-
obligation.cause.span,
485-
trait_def_id,
486-
violations);
487-
note_obligation_cause(infcx, &mut err, obligation);
488-
err.emit();
520+
let err = report_object_safety_error(infcx.tcx,
521+
obligation.cause.span,
522+
trait_def_id,
523+
warning_node_id,
524+
violations);
525+
if let Some(mut err) = err {
526+
note_obligation_cause(infcx, &mut err, obligation);
527+
err.emit();
528+
}
489529
}
490530

491531
ty::Predicate::ClosureKind(closure_def_id, kind) => {
@@ -514,6 +554,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
514554
"WF predicate not satisfied for {:?}",
515555
ty);
516556
}
557+
558+
ty::Predicate::Rfc1592(ref data) => {
559+
span_bug!(
560+
obligation.cause.span,
561+
"RFC1592 predicate not satisfied for {:?}",
562+
data);
563+
}
517564
}
518565
}
519566
}
@@ -537,58 +584,84 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
537584

538585
TraitNotObjectSafe(did) => {
539586
let violations = object_safety_violations(infcx.tcx, did);
540-
let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
541-
violations);
542-
note_obligation_cause(infcx, &mut err, obligation);
543-
err.emit();
587+
let err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
588+
warning_node_id,
589+
violations);
590+
if let Some(mut err) = err {
591+
note_obligation_cause(infcx, &mut err, obligation);
592+
err.emit();
593+
}
544594
}
545595
}
546596
}
547597

548598
pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>,
549599
span: Span,
550600
trait_def_id: DefId,
601+
warning_node_id: Option<ast::NodeId>,
551602
violations: Vec<ObjectSafetyViolation>)
552-
-> DiagnosticBuilder<'tcx>
603+
-> Option<DiagnosticBuilder<'tcx>>
553604
{
554-
let mut err = struct_span_err!(
555-
tcx.sess, span, E0038,
556-
"the trait `{}` cannot be made into an object",
557-
tcx.item_path_str(trait_def_id));
605+
let mut err = match warning_node_id {
606+
Some(_) => None,
607+
None => {
608+
Some(struct_span_err!(
609+
tcx.sess, span, E0038,
610+
"the trait `{}` cannot be made into an object",
611+
tcx.item_path_str(trait_def_id)))
612+
}
613+
};
558614

559615
let mut reported_violations = FnvHashSet();
560616
for violation in violations {
561617
if !reported_violations.insert(violation.clone()) {
562618
continue;
563619
}
564-
match violation {
620+
let buf;
621+
let note = match violation {
565622
ObjectSafetyViolation::SizedSelf => {
566-
err.note("the trait cannot require that `Self : Sized`");
623+
"the trait cannot require that `Self : Sized`"
567624
}
568625

569626
ObjectSafetyViolation::SupertraitSelf => {
570-
err.note("the trait cannot use `Self` as a type parameter \
571-
in the supertrait listing");
627+
"the trait cannot use `Self` as a type parameter \
628+
in the supertrait listing"
572629
}
573630

574631
ObjectSafetyViolation::Method(method,
575632
MethodViolationCode::StaticMethod) => {
576-
err.note(&format!("method `{}` has no receiver",
577-
method.name));
633+
buf = format!("method `{}` has no receiver",
634+
method.name);
635+
&buf
578636
}
579637

580638
ObjectSafetyViolation::Method(method,
581639
MethodViolationCode::ReferencesSelf) => {
582-
err.note(&format!("method `{}` references the `Self` type \
640+
buf = format!("method `{}` references the `Self` type \
583641
in its arguments or return type",
584-
method.name));
642+
method.name);
643+
&buf
585644
}
586645

587646
ObjectSafetyViolation::Method(method,
588647
MethodViolationCode::Generic) => {
589-
err.note(&format!("method `{}` has generic type parameters",
590-
method.name));
648+
buf = format!("method `{}` has generic type parameters",
649+
method.name);
650+
&buf
591651
}
652+
};
653+
match (warning_node_id, &mut err) {
654+
(Some(node_id), &mut None) => {
655+
tcx.sess.add_lint(
656+
::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
657+
node_id,
658+
span,
659+
note.to_string());
660+
}
661+
(None, &mut Some(ref mut err)) => {
662+
err.note(note);
663+
}
664+
_ => unreachable!()
592665
}
593666
}
594667
err
@@ -764,6 +837,9 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
764837
ObligationCauseCode::SliceOrArrayElem => {
765838
err.note("slice and array elements must have `Sized` type");
766839
}
840+
ObligationCauseCode::TupleElem => {
841+
err.note("tuple elements must have `Sized` type");
842+
}
767843
ObligationCauseCode::ProjectionWf(data) => {
768844
err.note(&format!("required so that the projection `{}` is well-formed",
769845
data));

0 commit comments

Comments
 (0)
Please sign in to comment.