Skip to content

Commit

Permalink
Auto merge of #57501 - petrochenkov:highvar, r=<try>
Browse files Browse the repository at this point in the history
[WIP] High priority resolutions for associated variants

cc #56225 (comment)
  • Loading branch information
bors committed Jan 10, 2019
2 parents 6ecad33 + dcaebe0 commit 5f78915
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 105 deletions.
7 changes: 7 additions & 0 deletions src/librustc/lint/builtin.rs
Expand Up @@ -149,6 +149,12 @@ declare_lint! {
"safe access to extern statics was erroneously allowed"
}

declare_lint! {
pub TYPE_VS_VARIANT_AMBIGUITY,
Forbid,
"type vs variant ambiguity"
}

declare_lint! {
pub SAFE_PACKED_BORROWS,
Warn,
Expand Down Expand Up @@ -400,6 +406,7 @@ impl LintPass for HardwiredLints {
CONST_ERR,
RENAMED_AND_REMOVED_LINTS,
SAFE_EXTERN_STATICS,
TYPE_VS_VARIANT_AMBIGUITY,
SAFE_PACKED_BORROWS,
PATTERNS_IN_FNS_WITHOUT_BODY,
LEGACY_DIRECTORY_OWNERSHIP,
Expand Down
51 changes: 31 additions & 20 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -1288,7 +1288,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
span: Span,
ty: Ty<'tcx>,
ty_path_def: Def,
item_segment: &hir::PathSegment)
item_segment: &hir::PathSegment,
permit_variants: bool)
-> (Ty<'tcx>, Def)
{
let tcx = self.tcx();
Expand All @@ -1298,11 +1299,38 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {

self.prohibit_generics(slice::from_ref(item_segment));

// Check if we have an enum variant here.
match ty.sty {
ty::Adt(adt_def, _) if adt_def.is_enum() => {
let variant_def = adt_def.variants.iter().find(|vd| {
tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
});
if let Some(variant_def) = variant_def {
if permit_variants {
check_type_alias_enum_variants_enabled(tcx, span);

let def = Def::Variant(variant_def.did);
tcx.check_stability(def.def_id(), Some(ref_id), span);
return (ty, def);
} else {
use rustc::lint::builtin::TYPE_VS_VARIANT_AMBIGUITY;
tcx.lint_node(
TYPE_VS_VARIANT_AMBIGUITY,
ref_id,
span,
"type vs variant ambiguity",
);
}
}
},
_ => (),
}

// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&ty.sty, ty_path_def) {
(_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// `Self` in an impl of a trait -- we have a concrete `self` type and a
// trait reference.
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
Some(trait_ref) => trait_ref,
Expand Down Expand Up @@ -1354,23 +1382,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
return (tcx.types.err, Def::Err);
}
_ => {
// Check if we have an enum variant.
match ty.sty {
ty::Adt(adt_def, _) if adt_def.is_enum() => {
let variant_def = adt_def.variants.iter().find(|vd| {
tcx.hygienic_eq(assoc_name, vd.ident, adt_def.did)
});
if let Some(variant_def) = variant_def {
check_type_alias_enum_variants_enabled(tcx, span);

let def = Def::Variant(variant_def.did);
tcx.check_stability(def.def_id(), Some(ref_id), span);
return (ty, def);
}
},
_ => (),
}

// Don't print `TyErr` to the user.
if !ty.references_error() {
self.report_ambiguous_associated_type(span,
Expand Down Expand Up @@ -1773,7 +1784,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
} else {
Def::Err
};
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment, false).0
}
hir::TyKind::Array(ref ty, ref length) => {
let length_def_id = tcx.hir().local_def_id(length.id);
Expand Down
63 changes: 28 additions & 35 deletions src/librustc_typeck/check/method/mod.rs
Expand Up @@ -408,45 +408,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

let tcx = self.tcx;

let mode = probe::Mode::Path;
match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, expr_id, ProbeScope::TraitsInScope) {
Ok(pick) => {
debug!("resolve_ufcs: pick={:?}", pick);
if let Some(import_id) = pick.import_id {
let import_def_id = tcx.hir().local_def_id(import_id);
debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
.unwrap().insert(import_def_id);
// Check if we have an enum variant here.
match self_ty.sty {
ty::Adt(adt_def, _) if adt_def.is_enum() => {
let variant_def = adt_def.variants.iter().find(|vd| {
tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
});
if let Some(variant_def) = variant_def {
check_type_alias_enum_variants_enabled(tcx, span);

let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
tcx.check_stability(def.def_id(), Some(expr_id), span);
return Ok(def);
}
},
_ => (),
}

let def = pick.item.def();
debug!("resolve_ufcs: def={:?}", def);
tcx.check_stability(def.def_id(), Some(expr_id), span);

Ok(def)
}
Err(err) => {
// Check if we have an enum variant.
match self_ty.sty {
ty::Adt(adt_def, _) if adt_def.is_enum() => {
let variant_def = adt_def.variants.iter().find(|vd| {
tcx.hygienic_eq(method_name, vd.ident, adt_def.did)
});
if let Some(variant_def) = variant_def {
check_type_alias_enum_variants_enabled(tcx, span);

let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind);
tcx.check_stability(def.def_id(), Some(expr_id), span);
return Ok(def);
}
},
_ => (),
}
let mode = probe::Mode::Path;
let pick = self.probe_for_name(span, mode, method_name, IsSuggestion(false),
self_ty, expr_id, ProbeScope::TraitsInScope)?;

Err(err)
}
if let Some(import_id) = pick.import_id {
let import_def_id = tcx.hir().local_def_id(import_id);
debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
.unwrap().insert(import_def_id);
}

let def = pick.item.def();
tcx.check_stability(def.def_id(), Some(expr_id), span);

Ok(def)
}

/// Find item with name `item_name` defined in impl/trait `def_id`
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Expand Up @@ -4623,7 +4623,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Def::Err
};
let (ty, def) = AstConv::associated_path_def_to_ty(self, node_id, path_span,
ty, def, segment);
ty, def, segment, true);

// Write back the new resolution.
let hir_id = self.tcx.hir().node_to_hir_id(node_id);
Expand Down
30 changes: 15 additions & 15 deletions src/librustc_typeck/lib.rs
Expand Up @@ -111,7 +111,7 @@ use rustc::infer::InferOk;
use rustc::lint;
use rustc::middle;
use rustc::session;
use rustc::session::config::nightly_options;
// use rustc::session::config::nightly_options;
use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
Expand All @@ -130,20 +130,20 @@ pub struct TypeAndSubsts<'tcx> {
ty: Ty<'tcx>,
}

fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
span: Span) {
if !tcx.features().type_alias_enum_variants {
let mut err = tcx.sess.struct_span_err(
span,
"enum variants on type aliases are experimental"
);
if nightly_options::is_nightly_build() {
help!(&mut err,
"add `#![feature(type_alias_enum_variants)]` to the \
crate attributes to enable");
}
err.emit();
}
fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(_tcx: TyCtxt<'a, 'gcx, 'tcx>,
_span: Span) {
// if !tcx.features().type_alias_enum_variants {
// let mut err = tcx.sess.struct_span_err(
// span,
// "enum variants on type aliases are experimental"
// );
// if nightly_options::is_nightly_build() {
// help!(&mut err,
// "add `#![feature(type_alias_enum_variants)]` to the \
// crate attributes to enable");
// }
// err.emit();
// }
}

fn require_c_abi_if_variadic(tcx: TyCtxt,
Expand Down
Expand Up @@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass

enum Foo {
Bar(i32),
Baz { i: i32 },
Expand Down

This file was deleted.

13 changes: 13 additions & 0 deletions src/test/ui/type-alias-enum-variants-priority-2.rs
@@ -0,0 +1,13 @@
#![feature(type_alias_enum_variants)]

enum E {
V(u8)
}

impl E {
fn V() {}
}

fn main() {
<E>::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied
}
12 changes: 12 additions & 0 deletions src/test/ui/type-alias-enum-variants-priority-2.stderr
@@ -0,0 +1,12 @@
error[E0061]: this function takes 1 parameter but 0 parameters were supplied
--> $DIR/type-alias-enum-variants-priority-2.rs:12:5
|
LL | V(u8)
| ----- defined here
...
LL | <E>::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied
| ^^^^^^^^ expected 1 parameter

error: aborting due to previous error

For more information about this error, try `rustc --explain E0061`.
17 changes: 17 additions & 0 deletions src/test/ui/type-alias-enum-variants-priority.rs
@@ -0,0 +1,17 @@
#![feature(type_alias_enum_variants)]

enum E {
V(u8)
}

trait Tr {
type V;
fn f() -> Self::V;
}

impl Tr for E {
type V = u8;
fn f() -> Self::V { loop {} } //~ ERROR type vs variant ambiguity
}

fn main() {}
10 changes: 10 additions & 0 deletions src/test/ui/type-alias-enum-variants-priority.stderr
@@ -0,0 +1,10 @@
error: type vs variant ambiguity
--> $DIR/type-alias-enum-variants-priority.rs:14:15
|
LL | fn f() -> Self::V { loop {} } //~ ERROR type vs variant ambiguity
| ^^^^^^^
|
= note: #[forbid(type_vs_variant_ambiguity)] on by default

error: aborting due to previous error

0 comments on commit 5f78915

Please sign in to comment.