Skip to content

Commit f53d379

Browse files
committed
Merge pull request #29262 from brson/beta-next
Beta next
2 parents 20eba40 + 0c48aae commit f53d379

File tree

5 files changed

+115
-15
lines changed

5 files changed

+115
-15
lines changed

Diff for: mk/main.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.4.0
1818
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
1919
# NB Make sure it starts with a dot to conform to semver pre-release
2020
# versions (section 9)
21-
CFG_PRERELEASE_VERSION=.3
21+
CFG_PRERELEASE_VERSION=.4
2222

2323
# Append a version-dependent hash to each library, so we can install different
2424
# versions in the same place

Diff for: src/librustc/middle/region.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use middle::ty::{self, Ty};
2424

2525
use std::cell::RefCell;
2626
use std::collections::hash_map::Entry;
27+
use std::fmt;
2728
use std::mem;
2829
use syntax::codemap::{self, Span};
2930
use syntax::ast::{self, NodeId};
@@ -34,9 +35,25 @@ use rustc_front::hir::{Block, Item, FnDecl, Arm, Pat, Stmt, Expr, Local};
3435
use rustc_front::util::stmt_id;
3536

3637
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
37-
RustcDecodable, Debug, Copy)]
38+
RustcDecodable, Copy)]
3839
pub struct CodeExtent(u32);
3940

41+
impl fmt::Debug for CodeExtent {
42+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43+
try!(write!(f, "CodeExtent({:?}", self.0));
44+
45+
try!(ty::tls::with_opt(|opt_tcx| {
46+
if let Some(tcx) = opt_tcx {
47+
let data = tcx.region_maps.code_extents.borrow()[self.0 as usize];
48+
try!(write!(f, "/{:?}", data));
49+
}
50+
Ok(())
51+
}));
52+
53+
write!(f, ")")
54+
}
55+
}
56+
4057
/// The root of everything. I should be using NonZero or profiling
4158
/// instead of this (probably).
4259
pub const ROOT_CODE_EXTENT : CodeExtent = CodeExtent(0);

Diff for: src/librustc/middle/traits/project.rs

+62-12
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,19 @@ pub struct MismatchedProjectionTypes<'tcx> {
5454

5555
#[derive(PartialEq, Eq, Debug)]
5656
enum ProjectionTyCandidate<'tcx> {
57+
// from a where-clause in the env or object type
5758
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
59+
60+
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
61+
TraitDef(ty::PolyProjectionPredicate<'tcx>),
62+
63+
// defined in an impl
5864
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
65+
66+
// closure return type
5967
Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
68+
69+
// fn pointer return type
6070
FnPointer(Ty<'tcx>),
6171
}
6272

@@ -491,7 +501,11 @@ fn project_type<'cx,'tcx>(
491501
candidates.vec.len(),
492502
candidates.ambiguous);
493503

494-
// We probably need some winnowing logic similar to select here.
504+
// Inherent ambiguity that prevents us from even enumerating the
505+
// candidates.
506+
if candidates.ambiguous {
507+
return Err(ProjectionTyError::TooManyCandidates);
508+
}
495509

496510
// Drop duplicates.
497511
//
@@ -512,10 +526,30 @@ fn project_type<'cx,'tcx>(
512526
}
513527
}
514528

515-
if candidates.ambiguous || candidates.vec.len() > 1 {
516-
return Err(ProjectionTyError::TooManyCandidates);
529+
// Prefer where-clauses. As in select, if there are multiple
530+
// candidates, we prefer where-clause candidates over impls. This
531+
// may seem a bit surprising, since impls are the source of
532+
// "truth" in some sense, but in fact some of the impls that SEEM
533+
// applicable are not, because of nested obligations. Where
534+
// clauses are the safer choice. See the comment on
535+
// `select::SelectionCandidate` and #21974 for more details.
536+
if candidates.vec.len() > 1 {
537+
debug!("retaining param-env candidates only from {:?}", candidates.vec);
538+
candidates.vec.retain(|c| match *c {
539+
ProjectionTyCandidate::ParamEnv(..) => true,
540+
ProjectionTyCandidate::Impl(..) |
541+
ProjectionTyCandidate::Closure(..) |
542+
ProjectionTyCandidate::TraitDef(..) |
543+
ProjectionTyCandidate::FnPointer(..) => false,
544+
});
545+
debug!("resulting candidate set: {:?}", candidates.vec);
546+
if candidates.vec.len() != 1 {
547+
return Err(ProjectionTyError::TooManyCandidates);
548+
}
517549
}
518550

551+
assert!(candidates.vec.len() <= 1);
552+
519553
match candidates.vec.pop() {
520554
Some(candidate) => {
521555
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
@@ -538,9 +572,14 @@ fn assemble_candidates_from_param_env<'cx,'tcx>(
538572
obligation_trait_ref: &ty::TraitRef<'tcx>,
539573
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
540574
{
575+
debug!("assemble_candidates_from_param_env(..)");
541576
let env_predicates = selcx.param_env().caller_bounds.iter().cloned();
542-
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
543-
candidate_set, env_predicates);
577+
assemble_candidates_from_predicates(selcx,
578+
obligation,
579+
obligation_trait_ref,
580+
candidate_set,
581+
ProjectionTyCandidate::ParamEnv,
582+
env_predicates);
544583
}
545584

546585
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
@@ -559,6 +598,8 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
559598
obligation_trait_ref: &ty::TraitRef<'tcx>,
560599
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
561600
{
601+
debug!("assemble_candidates_from_trait_def(..)");
602+
562603
// Check whether the self-type is itself a projection.
563604
let trait_ref = match obligation_trait_ref.self_ty().sty {
564605
ty::TyProjection(ref data) => data.trait_ref.clone(),
@@ -575,15 +616,20 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
575616
let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id);
576617
let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
577618
let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec());
578-
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
579-
candidate_set, bounds)
619+
assemble_candidates_from_predicates(selcx,
620+
obligation,
621+
obligation_trait_ref,
622+
candidate_set,
623+
ProjectionTyCandidate::TraitDef,
624+
bounds)
580625
}
581626

582627
fn assemble_candidates_from_predicates<'cx,'tcx,I>(
583628
selcx: &mut SelectionContext<'cx,'tcx>,
584629
obligation: &ProjectionTyObligation<'tcx>,
585630
obligation_trait_ref: &ty::TraitRef<'tcx>,
586631
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
632+
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
587633
env_predicates: I)
588634
where I: Iterator<Item=ty::Predicate<'tcx>>
589635
{
@@ -614,8 +660,7 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
614660
data, is_match, same_name);
615661

616662
if is_match {
617-
candidate_set.vec.push(
618-
ProjectionTyCandidate::ParamEnv(data.clone()));
663+
candidate_set.vec.push(ctor(data.clone()));
619664
}
620665
}
621666
_ => { }
@@ -647,8 +692,12 @@ fn assemble_candidates_from_object_type<'cx,'tcx>(
647692
.map(|p| p.to_predicate())
648693
.collect();
649694
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
650-
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
651-
candidate_set, env_predicates)
695+
assemble_candidates_from_predicates(selcx,
696+
obligation,
697+
obligation_trait_ref,
698+
candidate_set,
699+
ProjectionTyCandidate::ParamEnv,
700+
env_predicates)
652701
}
653702

654703
fn assemble_candidates_from_impls<'cx,'tcx>(
@@ -746,7 +795,8 @@ fn confirm_candidate<'cx,'tcx>(
746795
obligation);
747796

748797
match candidate {
749-
ProjectionTyCandidate::ParamEnv(poly_projection) => {
798+
ProjectionTyCandidate::ParamEnv(poly_projection) |
799+
ProjectionTyCandidate::TraitDef(poly_projection) => {
750800
confirm_param_env_candidate(selcx, obligation, poly_projection)
751801
}
752802

Diff for: src/librustc_driver/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub fn parse_pretty(sess: &Session,
9090
("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
9191
("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
9292
("hir", true) => PpmHir(PpmNormal),
93-
("hir,identified", true) => PpmHir(PpmExpandedIdentified),
93+
("hir,identified", true) => PpmHir(PpmIdentified),
9494
("hir,typed", true) => PpmHir(PpmTyped),
9595
("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default),
9696
("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),

Diff for: src/test/run-pass/issue-28871.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Regression test for #28871. The problem is that rustc encountered
12+
// two ways to project, one from a where clause and one from the where
13+
// clauses on the trait definition. (In fact, in this case, the where
14+
// clauses originated from the trait definition as well.) The true
15+
// cause of the error is that the trait definition where clauses are
16+
// not being normalized, and hence the two sources are considered in
17+
// conflict, and not a duplicate. Hacky solution is to prefer where
18+
// clauses over the data found in the trait definition.
19+
20+
trait T {
21+
type T;
22+
}
23+
24+
struct S;
25+
impl T for S {
26+
type T = S;
27+
}
28+
29+
trait T2 {
30+
type T: Iterator<Item=<S as T>::T>;
31+
}
32+
33+
fn main() { }

0 commit comments

Comments
 (0)