Get associated consts working in match patterns.
This commit is contained in:
parent
91ae5e31ab
commit
29eb550ee6
25 changed files with 611 additions and 199 deletions
|
@ -105,6 +105,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||||
match pat.node {
|
match pat.node {
|
||||||
ast::PatIdent(_, _, None) |
|
ast::PatIdent(_, _, None) |
|
||||||
ast::PatEnum(_, None) |
|
ast::PatEnum(_, None) |
|
||||||
|
ast::PatQPath(..) |
|
||||||
ast::PatLit(..) |
|
ast::PatLit(..) |
|
||||||
ast::PatRange(..) |
|
ast::PatRange(..) |
|
||||||
ast::PatWild(_) => {
|
ast::PatWild(_) => {
|
||||||
|
|
|
@ -439,7 +439,7 @@ impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> {
|
||||||
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
||||||
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
|
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
|
||||||
return match pat.node {
|
return match pat.node {
|
||||||
ast::PatIdent(..) | ast::PatEnum(..) => {
|
ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||||
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
||||||
match def {
|
match def {
|
||||||
Some(DefAssociatedConst(did, _)) |
|
Some(DefAssociatedConst(did, _)) |
|
||||||
|
@ -762,6 +762,9 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
||||||
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
||||||
_ => vec!(Single)
|
_ => vec!(Single)
|
||||||
},
|
},
|
||||||
|
ast::PatQPath(..) =>
|
||||||
|
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
||||||
|
been rewritten"),
|
||||||
ast::PatStruct(..) =>
|
ast::PatStruct(..) =>
|
||||||
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
||||||
|
@ -891,6 +894,11 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::PatQPath(_, _) => {
|
||||||
|
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
||||||
|
been rewritten")
|
||||||
|
}
|
||||||
|
|
||||||
ast::PatStruct(_, ref pattern_fields, _) => {
|
ast::PatStruct(_, ref pattern_fields, _) => {
|
||||||
// Is this a struct or an enum variant?
|
// Is this a struct or an enum variant?
|
||||||
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
||||||
|
|
|
@ -1147,7 +1147,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||||
let tcx = typer.tcx();
|
let tcx = typer.tcx();
|
||||||
|
|
||||||
match pat.node {
|
match pat.node {
|
||||||
ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
|
ast::PatEnum(_, _) | ast::PatQPath(..) |
|
||||||
|
ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
|
||||||
match def_map.get(&pat.id).map(|d| d.full_def()) {
|
match def_map.get(&pat.id).map(|d| d.full_def()) {
|
||||||
None => {
|
None => {
|
||||||
// no definition found: pat is not a
|
// no definition found: pat is not a
|
||||||
|
|
|
@ -1299,6 +1299,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::PatQPath(..) => {
|
||||||
|
// Lone constant: ignore
|
||||||
|
}
|
||||||
|
|
||||||
ast::PatIdent(_, _, Some(ref subpat)) => {
|
ast::PatIdent(_, _, Some(ref subpat)) => {
|
||||||
try!(self.cat_pattern_(cmt, &**subpat, op));
|
try!(self.cat_pattern_(cmt, &**subpat, op));
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
|
||||||
|
|
||||||
pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
|
pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
match pat.node {
|
match pat.node {
|
||||||
ast::PatLit(_) | ast::PatRange(_, _) => true,
|
ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
|
||||||
ast::PatEnum(_, _) |
|
ast::PatEnum(_, _) |
|
||||||
ast::PatIdent(_, _, None) |
|
ast::PatIdent(_, _, None) |
|
||||||
ast::PatStruct(..) => {
|
ast::PatStruct(..) => {
|
||||||
|
@ -60,7 +60,7 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
|
|
||||||
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
match pat.node {
|
match pat.node {
|
||||||
ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
|
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||||
match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
|
match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
|
||||||
_ => false
|
_ => false
|
||||||
|
@ -70,6 +70,22 @@ pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same as above, except that partially-resolved defs cause `false` to be
|
||||||
|
// returned instead of a panic.
|
||||||
|
pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
|
match pat.node {
|
||||||
|
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||||
|
match dm.borrow().get(&pat.id)
|
||||||
|
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
|
||||||
|
else { None } ) {
|
||||||
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
|
pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||||
match pat.node {
|
match pat.node {
|
||||||
ast::PatIdent(..) => {
|
ast::PatIdent(..) => {
|
||||||
|
|
|
@ -1091,7 +1091,6 @@ impl LintPass for NonUpperCaseGlobals {
|
||||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||||
// Lint for constants that look like binding identifiers (#7526)
|
// Lint for constants that look like binding identifiers (#7526)
|
||||||
match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
|
match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
|
||||||
(&ast::PatIdent(_, ref path1, _), Some(def::DefAssociatedConst(..))) |
|
|
||||||
(&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
|
(&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
|
||||||
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
|
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
|
||||||
path1.node, p.span);
|
path1.node, p.span);
|
||||||
|
|
|
@ -41,6 +41,7 @@ use self::TypeParameters::*;
|
||||||
use self::RibKind::*;
|
use self::RibKind::*;
|
||||||
use self::UseLexicalScopeFlag::*;
|
use self::UseLexicalScopeFlag::*;
|
||||||
use self::ModulePrefixResult::*;
|
use self::ModulePrefixResult::*;
|
||||||
|
use self::AssocItemResolveResult::*;
|
||||||
use self::NameSearchType::*;
|
use self::NameSearchType::*;
|
||||||
use self::BareIdentifierPatternResolution::*;
|
use self::BareIdentifierPatternResolution::*;
|
||||||
use self::ParentLink::*;
|
use self::ParentLink::*;
|
||||||
|
@ -70,7 +71,7 @@ use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate};
|
||||||
use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
|
use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
|
||||||
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
|
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
|
||||||
use syntax::ast::{Local, MethodImplItem, Name, NodeId};
|
use syntax::ast::{Local, MethodImplItem, Name, NodeId};
|
||||||
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
|
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit, PatQPath};
|
||||||
use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
|
use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
|
||||||
use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
|
use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
|
||||||
use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
|
use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
|
||||||
|
@ -331,6 +332,15 @@ enum ModulePrefixResult {
|
||||||
PrefixFound(Rc<Module>, usize)
|
PrefixFound(Rc<Module>, usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum AssocItemResolveResult {
|
||||||
|
/// Syntax such as `<T>::item`, which can't be resolved until type
|
||||||
|
/// checking.
|
||||||
|
TypecheckRequired,
|
||||||
|
/// We should have been able to resolve the associated item.
|
||||||
|
ResolveAttempt(Option<PathResolution>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
enum NameSearchType {
|
enum NameSearchType {
|
||||||
/// We're doing a name search in order to resolve a `use` directive.
|
/// We're doing a name search in order to resolve a `use` directive.
|
||||||
|
@ -2305,32 +2315,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
|
|
||||||
fn resolve_type(&mut self, ty: &Ty) {
|
fn resolve_type(&mut self, ty: &Ty) {
|
||||||
match ty.node {
|
match ty.node {
|
||||||
// `<T>::a::b::c` is resolved by typeck alone.
|
|
||||||
TyPath(Some(ast::QSelf { position: 0, .. }), _) => {}
|
|
||||||
|
|
||||||
TyPath(ref maybe_qself, ref path) => {
|
TyPath(ref maybe_qself, ref path) => {
|
||||||
let max_assoc_types = if let Some(ref qself) = *maybe_qself {
|
let resolution =
|
||||||
// Make sure the trait is valid.
|
match self.resolve_possibly_assoc_item(ty.id,
|
||||||
let _ = self.resolve_trait_reference(ty.id, path, 1);
|
maybe_qself.as_ref(),
|
||||||
path.segments.len() - qself.position
|
path,
|
||||||
} else {
|
TypeNS,
|
||||||
path.segments.len()
|
true) {
|
||||||
|
// `<T>::a::b::c` is resolved by typeck alone.
|
||||||
|
TypecheckRequired => {
|
||||||
|
// Resolve embedded types.
|
||||||
|
visit::walk_ty(self, ty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResolveAttempt(resolution) => resolution,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut resolution = None;
|
|
||||||
for depth in 0..max_assoc_types {
|
|
||||||
self.with_no_errors(|this| {
|
|
||||||
resolution = this.resolve_path(ty.id, path, depth, TypeNS, true);
|
|
||||||
});
|
|
||||||
if resolution.is_some() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
|
||||||
// A module is not a valid type.
|
|
||||||
resolution = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a path in the type namespace. Walk through scopes
|
// This is a path in the type namespace. Walk through scopes
|
||||||
// looking for it.
|
// looking for it.
|
||||||
match resolution {
|
match resolution {
|
||||||
|
@ -2489,10 +2489,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
|
|
||||||
PatEnum(ref path, _) => {
|
PatEnum(ref path, _) => {
|
||||||
// This must be an enum variant, struct or const.
|
// This must be an enum variant, struct or const.
|
||||||
if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) {
|
let resolution =
|
||||||
|
match self.resolve_possibly_assoc_item(pat_id, None,
|
||||||
|
path, ValueNS,
|
||||||
|
false) {
|
||||||
|
// The below shouldn't happen because all
|
||||||
|
// qualified paths should be in PatQPath.
|
||||||
|
TypecheckRequired =>
|
||||||
|
self.session.span_bug(
|
||||||
|
path.span,
|
||||||
|
"resolve_possibly_assoc_item claimed
|
||||||
|
that a path in PatEnum requires typecheck
|
||||||
|
to resolve, but qualified paths should be
|
||||||
|
PatQPath"),
|
||||||
|
ResolveAttempt(resolution) => resolution,
|
||||||
|
};
|
||||||
|
if let Some(path_res) = resolution {
|
||||||
match path_res.base_def {
|
match path_res.base_def {
|
||||||
DefVariant(..) | DefStruct(..) | DefConst(..) |
|
DefVariant(..) | DefStruct(..) | DefConst(..) => {
|
||||||
DefAssociatedConst(..) => {
|
|
||||||
self.record_def(pattern.id, path_res);
|
self.record_def(pattern.id, path_res);
|
||||||
}
|
}
|
||||||
DefStatic(..) => {
|
DefStatic(..) => {
|
||||||
|
@ -2502,10 +2516,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
use a `const` instead");
|
use a `const` instead");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.resolve_error(path.span,
|
// If anything ends up here entirely resolved,
|
||||||
|
// it's an error. If anything ends up here
|
||||||
|
// partially resolved, that's OK, because it may
|
||||||
|
// be a `T::CONST` that typeck will resolve to
|
||||||
|
// an inherent impl.
|
||||||
|
if path_res.depth == 0 {
|
||||||
|
self.resolve_error(
|
||||||
|
path.span,
|
||||||
&format!("`{}` is not an enum variant, struct or const",
|
&format!("`{}` is not an enum variant, struct or const",
|
||||||
token::get_ident(
|
token::get_ident(
|
||||||
path.segments.last().unwrap().identifier)));
|
path.segments.last().unwrap().identifier)));
|
||||||
|
} else {
|
||||||
|
self.record_def(pattern.id, path_res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2516,6 +2540,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
visit::walk_path(self, path);
|
visit::walk_path(self, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PatQPath(ref qself, ref path) => {
|
||||||
|
// Associated constants only.
|
||||||
|
let resolution =
|
||||||
|
match self.resolve_possibly_assoc_item(pat_id, Some(qself),
|
||||||
|
path, ValueNS,
|
||||||
|
false) {
|
||||||
|
TypecheckRequired => {
|
||||||
|
// All `<T>::CONST` should end up here, and will
|
||||||
|
// require use of the trait map to resolve
|
||||||
|
// during typechecking.
|
||||||
|
let const_name = path.segments.last().unwrap()
|
||||||
|
.identifier.name;
|
||||||
|
let traits = self.get_traits_containing_item(const_name);
|
||||||
|
self.trait_map.insert(pattern.id, traits);
|
||||||
|
visit::walk_pat(self, pattern);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ResolveAttempt(resolution) => resolution,
|
||||||
|
};
|
||||||
|
if let Some(path_res) = resolution {
|
||||||
|
match path_res.base_def {
|
||||||
|
// All `<T as Trait>::CONST` should end up here, and
|
||||||
|
// have the trait already selected.
|
||||||
|
DefAssociatedConst(..) => {
|
||||||
|
self.record_def(pattern.id, path_res);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.resolve_error(path.span,
|
||||||
|
&format!("`{}` is not an associated const",
|
||||||
|
token::get_ident(
|
||||||
|
path.segments.last().unwrap().identifier)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.resolve_error(path.span,
|
||||||
|
&format!("unresolved associated const `{}`",
|
||||||
|
token::get_ident(path.segments.last().unwrap().identifier)));
|
||||||
|
}
|
||||||
|
visit::walk_pat(self, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
PatStruct(ref path, _, _) => {
|
PatStruct(ref path, _, _) => {
|
||||||
match self.resolve_path(pat_id, path, 0, TypeNS, false) {
|
match self.resolve_path(pat_id, path, 0, TypeNS, false) {
|
||||||
Some(definition) => {
|
Some(definition) => {
|
||||||
|
@ -2605,6 +2670,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles paths that may refer to associated items
|
||||||
|
fn resolve_possibly_assoc_item(&mut self,
|
||||||
|
id: NodeId,
|
||||||
|
maybe_qself: Option<&ast::QSelf>,
|
||||||
|
path: &Path,
|
||||||
|
namespace: Namespace,
|
||||||
|
check_ribs: bool)
|
||||||
|
-> AssocItemResolveResult
|
||||||
|
{
|
||||||
|
match maybe_qself {
|
||||||
|
Some(&ast::QSelf { position: 0, .. }) =>
|
||||||
|
return TypecheckRequired,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let max_assoc_types = if let Some(qself) = maybe_qself {
|
||||||
|
// Make sure the trait is valid.
|
||||||
|
let _ = self.resolve_trait_reference(id, path, 1);
|
||||||
|
path.segments.len() - qself.position
|
||||||
|
} else {
|
||||||
|
path.segments.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut resolution = self.with_no_errors(|this| {
|
||||||
|
this.resolve_path(id, path, 0, namespace, check_ribs)
|
||||||
|
});
|
||||||
|
for depth in 1..max_assoc_types {
|
||||||
|
if resolution.is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.with_no_errors(|this| {
|
||||||
|
resolution = this.resolve_path(id, path, depth,
|
||||||
|
TypeNS, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
||||||
|
// A module is not a valid type or value.
|
||||||
|
resolution = None;
|
||||||
|
}
|
||||||
|
ResolveAttempt(resolution)
|
||||||
|
}
|
||||||
|
|
||||||
/// If `check_ribs` is true, checks the local definitions first; i.e.
|
/// If `check_ribs` is true, checks the local definitions first; i.e.
|
||||||
/// doesn't skip straight to the containing module.
|
/// doesn't skip straight to the containing module.
|
||||||
/// Skips `path_depth` trailing segments, which is also reflected in the
|
/// Skips `path_depth` trailing segments, which is also reflected in the
|
||||||
|
@ -3119,39 +3225,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
|
|
||||||
// Next, resolve the node.
|
// Next, resolve the node.
|
||||||
match expr.node {
|
match expr.node {
|
||||||
|
ExprPath(ref maybe_qself, ref path) => {
|
||||||
|
let resolution =
|
||||||
|
match self.resolve_possibly_assoc_item(expr.id,
|
||||||
|
maybe_qself.as_ref(),
|
||||||
|
path,
|
||||||
|
ValueNS,
|
||||||
|
true) {
|
||||||
// `<T>::a::b::c` is resolved by typeck alone.
|
// `<T>::a::b::c` is resolved by typeck alone.
|
||||||
ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => {
|
TypecheckRequired => {
|
||||||
let method_name = path.segments.last().unwrap().identifier.name;
|
let method_name = path.segments.last().unwrap().identifier.name;
|
||||||
let traits = self.search_for_traits_containing_method(method_name);
|
let traits = self.get_traits_containing_item(method_name);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
ResolveAttempt(resolution) => resolution,
|
||||||
ExprPath(ref maybe_qself, ref path) => {
|
|
||||||
let max_assoc_types = if let Some(ref qself) = *maybe_qself {
|
|
||||||
// Make sure the trait is valid.
|
|
||||||
let _ = self.resolve_trait_reference(expr.id, path, 1);
|
|
||||||
path.segments.len() - qself.position
|
|
||||||
} else {
|
|
||||||
path.segments.len()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut resolution = self.with_no_errors(|this| {
|
|
||||||
this.resolve_path(expr.id, path, 0, ValueNS, true)
|
|
||||||
});
|
|
||||||
for depth in 1..max_assoc_types {
|
|
||||||
if resolution.is_some() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
self.with_no_errors(|this| {
|
|
||||||
resolution = this.resolve_path(expr.id, path, depth, TypeNS, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
|
||||||
// A module is not a valid type or value.
|
|
||||||
resolution = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a local path in the value namespace. Walk through
|
// This is a local path in the value namespace. Walk through
|
||||||
// scopes looking for it.
|
// scopes looking for it.
|
||||||
if let Some(path_res) = resolution {
|
if let Some(path_res) = resolution {
|
||||||
|
@ -3181,7 +3272,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
// so they can be completed during typeck.
|
// so they can be completed during typeck.
|
||||||
if path_res.depth != 0 {
|
if path_res.depth != 0 {
|
||||||
let method_name = path.segments.last().unwrap().identifier.name;
|
let method_name = path.segments.last().unwrap().identifier.name;
|
||||||
let traits = self.search_for_traits_containing_method(method_name);
|
let traits = self.get_traits_containing_item(method_name);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3339,14 +3430,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
// field, we need to add any trait methods we find that match
|
// field, we need to add any trait methods we find that match
|
||||||
// the field name so that we can do some nice error reporting
|
// the field name so that we can do some nice error reporting
|
||||||
// later on in typeck.
|
// later on in typeck.
|
||||||
let traits = self.search_for_traits_containing_method(ident.node.name);
|
let traits = self.get_traits_containing_item(ident.node.name);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
ExprMethodCall(ident, _, _) => {
|
ExprMethodCall(ident, _, _) => {
|
||||||
debug!("(recording candidate traits for expr) recording \
|
debug!("(recording candidate traits for expr) recording \
|
||||||
traits for {}",
|
traits for {}",
|
||||||
expr.id);
|
expr.id);
|
||||||
let traits = self.search_for_traits_containing_method(ident.node.name);
|
let traits = self.get_traits_containing_item(ident.node.name);
|
||||||
self.trait_map.insert(expr.id, traits);
|
self.trait_map.insert(expr.id, traits);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -3355,8 +3446,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
|
fn get_traits_containing_item(&mut self, name: Name) -> Vec<DefId> {
|
||||||
debug!("(searching for traits containing method) looking for '{}'",
|
debug!("(getting traits containing item) looking for '{}'",
|
||||||
token::get_name(name));
|
token::get_name(name));
|
||||||
|
|
||||||
fn add_trait_info(found_traits: &mut Vec<DefId>,
|
fn add_trait_info(found_traits: &mut Vec<DefId>,
|
||||||
|
|
|
@ -1044,7 +1044,8 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::PatEnum(ref path, _) => {
|
ast::PatEnum(ref path, _) |
|
||||||
|
ast::PatQPath(_, ref path) => {
|
||||||
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
|
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
|
||||||
visit::walk_pat(self, p);
|
visit::walk_pat(self, p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1809,7 +1809,8 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
ast::PatMac(..) => {
|
ast::PatMac(..) => {
|
||||||
bcx.sess().span_bug(pat.span, "unexpanded macro");
|
bcx.sess().span_bug(pat.span, "unexpanded macro");
|
||||||
}
|
}
|
||||||
ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => ()
|
ast::PatQPath(..) | ast::PatWild(_) | ast::PatLit(_) |
|
||||||
|
ast::PatRange(_, _) => ()
|
||||||
}
|
}
|
||||||
return bcx;
|
return bcx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3437,6 +3437,10 @@ fn create_scope_map(cx: &CrateContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::PatQPath(..) => {
|
||||||
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
ast::PatStruct(_, ref field_pats, _) => {
|
ast::PatStruct(_, ref field_pats, _) => {
|
||||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,14 @@
|
||||||
use middle::const_eval;
|
use middle::const_eval;
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::infer;
|
use middle::infer;
|
||||||
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
|
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
|
||||||
|
use middle::pat_util::pat_is_resolved_const;
|
||||||
|
use middle::privacy::{AllPublic, LastMod};
|
||||||
use middle::subst::Substs;
|
use middle::subst::Substs;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
|
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
|
||||||
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
|
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
|
||||||
use check::{instantiate_path, structurally_resolved_type};
|
use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
|
||||||
use require_same_types;
|
use require_same_types;
|
||||||
use util::nodemap::FnvHashMap;
|
use util::nodemap::FnvHashMap;
|
||||||
use util::ppaux::Repr;
|
use util::ppaux::Repr;
|
||||||
|
@ -118,7 +120,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
// subtyping doesn't matter here, as the value is some kind of scalar
|
// subtyping doesn't matter here, as the value is some kind of scalar
|
||||||
demand::eqtype(fcx, pat.span, expected, lhs_ty);
|
demand::eqtype(fcx, pat.span, expected, lhs_ty);
|
||||||
}
|
}
|
||||||
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
|
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => {
|
||||||
let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
|
let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
|
||||||
let const_scheme = ty::lookup_item_type(tcx, const_did);
|
let const_scheme = ty::lookup_item_type(tcx, const_did);
|
||||||
assert!(const_scheme.generics.is_empty());
|
assert!(const_scheme.generics.is_empty());
|
||||||
|
@ -181,6 +183,37 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
let subpats = subpats.as_ref().map(|v| &v[..]);
|
let subpats = subpats.as_ref().map(|v| &v[..]);
|
||||||
check_pat_enum(pcx, pat, path, subpats, expected);
|
check_pat_enum(pcx, pat, path, subpats, expected);
|
||||||
}
|
}
|
||||||
|
ast::PatQPath(ref qself, ref path) => {
|
||||||
|
let self_ty = fcx.to_ty(&qself.ty);
|
||||||
|
let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
|
||||||
|
d
|
||||||
|
} else if qself.position == 0 {
|
||||||
|
def::PathResolution {
|
||||||
|
// This is just a sentinel for finish_resolving_def_to_ty.
|
||||||
|
base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
|
||||||
|
last_private: LastMod(AllPublic),
|
||||||
|
depth: path.segments.len()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcx.sess.span_bug(pat.span,
|
||||||
|
&format!("unbound path {}", pat.repr(tcx)))
|
||||||
|
};
|
||||||
|
if let Some((opt_ty, segments, def)) =
|
||||||
|
resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
|
||||||
|
path, pat.span, pat.id) {
|
||||||
|
if check_assoc_item_is_const(pcx, def, pat.span) {
|
||||||
|
let scheme = ty::lookup_item_type(tcx, def.def_id());
|
||||||
|
let predicates = ty::lookup_predicates(tcx, def.def_id());
|
||||||
|
instantiate_path(fcx, segments,
|
||||||
|
scheme, &predicates,
|
||||||
|
opt_ty, def, pat.span, pat.id);
|
||||||
|
let const_ty = fcx.node_ty(pat.id);
|
||||||
|
demand::suptype(fcx, pat.span, expected, const_ty);
|
||||||
|
} else {
|
||||||
|
fcx.write_error(pat.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::PatStruct(ref path, ref fields, etc) => {
|
ast::PatStruct(ref path, ref fields, etc) => {
|
||||||
check_pat_struct(pcx, pat, path, fields, etc, expected);
|
check_pat_struct(pcx, pat, path, fields, etc, expected);
|
||||||
}
|
}
|
||||||
|
@ -331,6 +364,21 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
// subtyping.
|
// subtyping.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
|
||||||
|
match def {
|
||||||
|
def::DefAssociatedConst(..) => true,
|
||||||
|
def::DefMethod(..) => {
|
||||||
|
span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
|
||||||
|
"associated items in match patterns must be constants");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in
|
||||||
|
check_assoc_item_is_const");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
span: Span, expected: Ty<'tcx>,
|
span: Span, expected: Ty<'tcx>,
|
||||||
inner: &ast::Pat) -> bool {
|
inner: &ast::Pat) -> bool {
|
||||||
|
@ -532,7 +580,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
let fcx = pcx.fcx;
|
let fcx = pcx.fcx;
|
||||||
let tcx = pcx.fcx.ccx.tcx;
|
let tcx = pcx.fcx.ccx.tcx;
|
||||||
|
|
||||||
let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
|
let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap();
|
||||||
|
|
||||||
|
let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
|
||||||
|
None, path,
|
||||||
|
pat.span, pat.id) {
|
||||||
|
Some(resolution) => resolution,
|
||||||
|
// Error handling done inside resolve_ty_and_def_ufcs, so if
|
||||||
|
// resolution fails just return.
|
||||||
|
None => {return;}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Items that were partially resolved before should have been resolved to
|
||||||
|
// associated constants (i.e. not methods).
|
||||||
|
if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
|
||||||
|
fcx.write_error(pat.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let enum_def = def.variant_def_ids()
|
let enum_def = def.variant_def_ids()
|
||||||
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
|
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
|
||||||
|
|
||||||
|
@ -547,13 +612,23 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||||
} else {
|
} else {
|
||||||
ctor_scheme
|
ctor_scheme
|
||||||
};
|
};
|
||||||
instantiate_path(pcx.fcx, &path.segments,
|
instantiate_path(pcx.fcx, segments,
|
||||||
path_scheme, &ctor_predicates,
|
path_scheme, &ctor_predicates,
|
||||||
None, def, pat.span, pat.id);
|
opt_ty, def, pat.span, pat.id);
|
||||||
|
|
||||||
|
// If we didn't have a fully resolved path to start with, we had an
|
||||||
|
// associated const, and we should quit now, since the rest of this
|
||||||
|
// function uses checks specific to structs and enums.
|
||||||
|
if path_res.depth != 0 {
|
||||||
|
let pat_ty = fcx.node_ty(pat.id);
|
||||||
|
demand::suptype(fcx, pat.span, expected, pat_ty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let pat_ty = fcx.node_ty(pat.id);
|
let pat_ty = fcx.node_ty(pat.id);
|
||||||
demand::eqtype(fcx, pat.span, expected, pat_ty);
|
demand::eqtype(fcx, pat.span, expected, pat_ty);
|
||||||
|
|
||||||
|
|
||||||
let real_path_ty = fcx.node_ty(pat.id);
|
let real_path_ty = fcx.node_ty(pat.id);
|
||||||
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
|
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
|
||||||
ty::ty_enum(enum_def_id, expected_substs)
|
ty::ty_enum(enum_def_id, expected_substs)
|
||||||
|
|
|
@ -3230,53 +3230,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
&format!("unbound path {}", expr.repr(tcx)))
|
&format!("unbound path {}", expr.repr(tcx)))
|
||||||
};
|
};
|
||||||
|
|
||||||
let def = path_res.base_def;
|
if let Some((opt_ty, segments, def)) =
|
||||||
if path_res.depth == 0 {
|
resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
|
||||||
|
expr.span, expr.id) {
|
||||||
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
|
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
|
||||||
expr.span,
|
expr.span,
|
||||||
def);
|
def);
|
||||||
instantiate_path(fcx,
|
instantiate_path(fcx,
|
||||||
&path.segments,
|
segments,
|
||||||
scheme,
|
scheme,
|
||||||
&predicates,
|
&predicates,
|
||||||
opt_self_ty,
|
opt_ty,
|
||||||
def,
|
def,
|
||||||
expr.span,
|
expr.span,
|
||||||
id);
|
id);
|
||||||
} else {
|
|
||||||
let ty_segments = path.segments.init();
|
|
||||||
let base_ty_end = path.segments.len() - path_res.depth;
|
|
||||||
let ty = astconv::finish_resolving_def_to_ty(fcx,
|
|
||||||
fcx,
|
|
||||||
expr.span,
|
|
||||||
PathParamMode::Optional,
|
|
||||||
&def,
|
|
||||||
opt_self_ty,
|
|
||||||
&ty_segments[..base_ty_end],
|
|
||||||
&ty_segments[base_ty_end..]);
|
|
||||||
let method_segment = path.segments.last().unwrap();
|
|
||||||
let method_name = method_segment.identifier.name;
|
|
||||||
match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
|
|
||||||
Ok((def, lp)) => {
|
|
||||||
// Write back the new resolution.
|
|
||||||
tcx.def_map.borrow_mut().insert(id, def::PathResolution {
|
|
||||||
base_def: def,
|
|
||||||
last_private: path_res.last_private.or(lp),
|
|
||||||
depth: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
let (scheme, predicates) =
|
|
||||||
type_scheme_and_predicates_for_def(fcx, expr.span, def);
|
|
||||||
instantiate_path(fcx, slice::ref_slice(method_segment),
|
|
||||||
scheme, &predicates,
|
|
||||||
Some(ty), def, expr.span, id);
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
method::report_error(fcx, expr.span, ty,
|
|
||||||
method_name, None, error);
|
|
||||||
fcx.write_error(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We always require that the type provided as the value for
|
// We always require that the type provided as the value for
|
||||||
|
@ -3738,6 +3705,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||||
unifier();
|
unifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
|
||||||
|
path_res: def::PathResolution,
|
||||||
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
|
path: &'a ast::Path,
|
||||||
|
span: Span,
|
||||||
|
node_id: ast::NodeId)
|
||||||
|
-> Option<(Option<Ty<'tcx>>,
|
||||||
|
&'a [ast::PathSegment],
|
||||||
|
def::Def)>
|
||||||
|
{
|
||||||
|
// If fully resolved already, we don't have to do anything.
|
||||||
|
if path_res.depth == 0 {
|
||||||
|
Some((opt_self_ty, &path.segments, path_res.base_def))
|
||||||
|
} else {
|
||||||
|
let mut def = path_res.base_def;
|
||||||
|
let ty_segments = path.segments.init();
|
||||||
|
let base_ty_end = path.segments.len() - path_res.depth;
|
||||||
|
let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span,
|
||||||
|
PathParamMode::Optional,
|
||||||
|
&mut def,
|
||||||
|
opt_self_ty,
|
||||||
|
&ty_segments[..base_ty_end],
|
||||||
|
&ty_segments[base_ty_end..]);
|
||||||
|
let item_segment = path.segments.last().unwrap();
|
||||||
|
let item_name = item_segment.identifier.name;
|
||||||
|
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
|
||||||
|
Ok((def, lp)) => {
|
||||||
|
// Write back the new resolution.
|
||||||
|
fcx.ccx.tcx.def_map.borrow_mut()
|
||||||
|
.insert(node_id, def::PathResolution {
|
||||||
|
base_def: def,
|
||||||
|
last_private: path_res.last_private.or(lp),
|
||||||
|
depth: 0
|
||||||
|
});
|
||||||
|
Some((Some(ty), slice::ref_slice(item_segment), def))
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
method::report_error(fcx, span, ty,
|
||||||
|
item_name, None, error);
|
||||||
|
fcx.write_error(node_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn constrain_path_type_parameters(fcx: &FnCtxt,
|
fn constrain_path_type_parameters(fcx: &FnCtxt,
|
||||||
expr: &ast::Expr)
|
expr: &ast::Expr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -180,6 +180,7 @@ register_diagnostics! {
|
||||||
E0324, // implemented a method when another trait item expected
|
E0324, // implemented a method when another trait item expected
|
||||||
E0325, // implemented an associated type when another trait item expected
|
E0325, // implemented an associated type when another trait item expected
|
||||||
E0326, // associated const implemented with different type from trait
|
E0326, // associated const implemented with different type from trait
|
||||||
|
E0327, // referred to method instead of constant in match pattern
|
||||||
E0366, // dropck forbid specialization to concrete type or region
|
E0366, // dropck forbid specialization to concrete type or region
|
||||||
E0367, // dropck forbid specialization to predicate not in struct/enum
|
E0367, // dropck forbid specialization to predicate not in struct/enum
|
||||||
E0368, // binary operation `<op>=` cannot be applied to types
|
E0368, // binary operation `<op>=` cannot be applied to types
|
||||||
|
|
|
@ -2522,6 +2522,8 @@ fn name_from_pat(p: &ast::Pat) -> String {
|
||||||
PatWild(PatWildMulti) => "..".to_string(),
|
PatWild(PatWildMulti) => "..".to_string(),
|
||||||
PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
|
PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
|
||||||
PatEnum(ref p, _) => path_to_string(p),
|
PatEnum(ref p, _) => path_to_string(p),
|
||||||
|
PatQPath(..) => panic!("tried to get argument name from PatQPath, \
|
||||||
|
which is not allowed in function arguments"),
|
||||||
PatStruct(ref name, ref fields, etc) => {
|
PatStruct(ref name, ref fields, etc) => {
|
||||||
format!("{} {{ {}{} }}", path_to_string(name),
|
format!("{} {{ {}{} }}", path_to_string(name),
|
||||||
fields.iter().map(|&Spanned { node: ref fp, .. }|
|
fields.iter().map(|&Spanned { node: ref fp, .. }|
|
||||||
|
|
|
@ -599,6 +599,12 @@ pub enum Pat_ {
|
||||||
/// "None" means a * pattern where we don't bind the fields to names.
|
/// "None" means a * pattern where we don't bind the fields to names.
|
||||||
PatEnum(Path, Option<Vec<P<Pat>>>),
|
PatEnum(Path, Option<Vec<P<Pat>>>),
|
||||||
|
|
||||||
|
/// An associated const named using the qualified path `<T>::CONST` or
|
||||||
|
/// `<T as Trait>::CONST`. Associated consts from inherent impls can be
|
||||||
|
/// refered to as simply `T::CONST`, in which case they will end up as
|
||||||
|
/// PatEnum, and the resolver will have to sort that out.
|
||||||
|
PatQPath(QSelf, Path),
|
||||||
|
|
||||||
/// Destructuring of a struct, e.g. `Foo {x, y, ..}`
|
/// Destructuring of a struct, e.g. `Foo {x, y, ..}`
|
||||||
/// The `bool` is `true` in the presence of a `..`
|
/// The `bool` is `true` in the presence of a `..`
|
||||||
PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
|
PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
|
||||||
|
|
|
@ -579,7 +579,7 @@ pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
|
||||||
}
|
}
|
||||||
PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
|
PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
|
||||||
PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
|
PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
|
||||||
PatEnum(_, _) => {
|
PatEnum(_, _) | PatQPath(_, _) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1134,6 +1134,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
||||||
PatEnum(folder.fold_path(pth),
|
PatEnum(folder.fold_path(pth),
|
||||||
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
|
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
|
||||||
}
|
}
|
||||||
|
PatQPath(qself, pth) => {
|
||||||
|
let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
|
||||||
|
PatQPath(qself, folder.fold_path(pth))
|
||||||
|
}
|
||||||
PatStruct(pth, fields, etc) => {
|
PatStruct(pth, fields, etc) => {
|
||||||
let pth = folder.fold_path(pth);
|
let pth = folder.fold_path(pth);
|
||||||
let fs = fields.move_map(|f| {
|
let fs = fields.move_map(|f| {
|
||||||
|
|
|
@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
|
||||||
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
|
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
|
||||||
use ast::{MutTy, BiMul, Mutability};
|
use ast::{MutTy, BiMul, Mutability};
|
||||||
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
|
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
|
||||||
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
|
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
|
||||||
use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
|
use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
|
||||||
|
use ast::PatWildSingle;
|
||||||
use ast::{PolyTraitRef, QSelf};
|
use ast::{PolyTraitRef, QSelf};
|
||||||
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
|
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
|
||||||
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
|
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
|
||||||
|
@ -109,6 +110,15 @@ pub enum PathParsingMode {
|
||||||
LifetimeAndTypesWithColons,
|
LifetimeAndTypesWithColons,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How to parse a qualified path, whether to allow trailing parameters.
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum QPathParsingMode {
|
||||||
|
/// No trailing parameters, e.g. `<T as Trait>::Item`
|
||||||
|
NoParameters,
|
||||||
|
/// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
|
||||||
|
MaybeParameters,
|
||||||
|
}
|
||||||
|
|
||||||
/// How to parse a bound, whether to allow bound modifiers such as `?`.
|
/// How to parse a bound, whether to allow bound modifiers such as `?`.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum BoundParsingMode {
|
pub enum BoundParsingMode {
|
||||||
|
@ -1345,36 +1355,9 @@ impl<'a> Parser<'a> {
|
||||||
try!(self.expect(&token::CloseDelim(token::Paren)));
|
try!(self.expect(&token::CloseDelim(token::Paren)));
|
||||||
TyTypeof(e)
|
TyTypeof(e)
|
||||||
} else if try!(self.eat_lt()) {
|
} else if try!(self.eat_lt()) {
|
||||||
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
|
|
||||||
let self_type = try!(self.parse_ty_sum());
|
|
||||||
|
|
||||||
let mut path = if try!(self.eat_keyword(keywords::As) ){
|
let (qself, path) =
|
||||||
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||||
} else {
|
|
||||||
ast::Path {
|
|
||||||
span: self.span,
|
|
||||||
global: false,
|
|
||||||
segments: vec![]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let qself = QSelf {
|
|
||||||
ty: self_type,
|
|
||||||
position: path.segments.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
try!(self.expect(&token::Gt));
|
|
||||||
try!(self.expect(&token::ModSep));
|
|
||||||
|
|
||||||
path.segments.push(ast::PathSegment {
|
|
||||||
identifier: try!(self.parse_ident()),
|
|
||||||
parameters: ast::PathParameters::none()
|
|
||||||
});
|
|
||||||
|
|
||||||
if path.segments.len() == 1 {
|
|
||||||
path.span.lo = self.last_span.lo;
|
|
||||||
}
|
|
||||||
path.span.hi = self.last_span.hi;
|
|
||||||
|
|
||||||
TyPath(Some(qself), path)
|
TyPath(Some(qself), path)
|
||||||
} else if self.check(&token::ModSep) ||
|
} else if self.check(&token::ModSep) ||
|
||||||
|
@ -1591,6 +1574,61 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
|
||||||
|
// Assumes that the leading `<` has been parsed already.
|
||||||
|
pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
|
||||||
|
-> PResult<(QSelf, ast::Path)> {
|
||||||
|
let self_type = try!(self.parse_ty_sum());
|
||||||
|
let mut path = if try!(self.eat_keyword(keywords::As)) {
|
||||||
|
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
||||||
|
} else {
|
||||||
|
ast::Path {
|
||||||
|
span: self.span,
|
||||||
|
global: false,
|
||||||
|
segments: vec![]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let qself = QSelf {
|
||||||
|
ty: self_type,
|
||||||
|
position: path.segments.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
try!(self.expect(&token::Gt));
|
||||||
|
try!(self.expect(&token::ModSep));
|
||||||
|
|
||||||
|
let item_name = try!(self.parse_ident());
|
||||||
|
let parameters = match mode {
|
||||||
|
QPathParsingMode::NoParameters => ast::PathParameters::none(),
|
||||||
|
QPathParsingMode::MaybeParameters => {
|
||||||
|
if try!(self.eat(&token::ModSep)) {
|
||||||
|
try!(self.expect_lt());
|
||||||
|
// Consumed `item::<`, go look for types
|
||||||
|
let (lifetimes, types, bindings) =
|
||||||
|
try!(self.parse_generic_values_after_lt());
|
||||||
|
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
||||||
|
lifetimes: lifetimes,
|
||||||
|
types: OwnedSlice::from_vec(types),
|
||||||
|
bindings: OwnedSlice::from_vec(bindings),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ast::PathParameters::none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
path.segments.push(ast::PathSegment {
|
||||||
|
identifier: item_name,
|
||||||
|
parameters: parameters
|
||||||
|
});
|
||||||
|
|
||||||
|
if path.segments.len() == 1 {
|
||||||
|
path.span.lo = self.last_span.lo;
|
||||||
|
}
|
||||||
|
path.span.hi = self.last_span.hi;
|
||||||
|
|
||||||
|
Ok((qself, path))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a path and optional type parameter bounds, depending on the
|
/// Parses a path and optional type parameter bounds, depending on the
|
||||||
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
|
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
|
||||||
/// bounds are permitted and whether `::` must precede type parameter
|
/// bounds are permitted and whether `::` must precede type parameter
|
||||||
|
@ -2054,49 +2092,10 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if try!(self.eat_lt()){
|
if try!(self.eat_lt()){
|
||||||
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
|
|
||||||
let self_type = try!(self.parse_ty_sum());
|
|
||||||
let mut path = if try!(self.eat_keyword(keywords::As) ){
|
|
||||||
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
|
||||||
} else {
|
|
||||||
ast::Path {
|
|
||||||
span: self.span,
|
|
||||||
global: false,
|
|
||||||
segments: vec![]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let qself = QSelf {
|
|
||||||
ty: self_type,
|
|
||||||
position: path.segments.len()
|
|
||||||
};
|
|
||||||
try!(self.expect(&token::Gt));
|
|
||||||
try!(self.expect(&token::ModSep));
|
|
||||||
|
|
||||||
let item_name = try!(self.parse_ident());
|
let (qself, path) =
|
||||||
let parameters = if try!(self.eat(&token::ModSep) ){
|
try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
|
||||||
try!(self.expect_lt());
|
|
||||||
// Consumed `item::<`, go look for types
|
|
||||||
let (lifetimes, types, bindings) =
|
|
||||||
try!(self.parse_generic_values_after_lt());
|
|
||||||
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
|
||||||
lifetimes: lifetimes,
|
|
||||||
types: OwnedSlice::from_vec(types),
|
|
||||||
bindings: OwnedSlice::from_vec(bindings),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ast::PathParameters::none()
|
|
||||||
};
|
|
||||||
path.segments.push(ast::PathSegment {
|
|
||||||
identifier: item_name,
|
|
||||||
parameters: parameters
|
|
||||||
});
|
|
||||||
|
|
||||||
if path.segments.len() == 1 {
|
|
||||||
path.span.lo = self.last_span.lo;
|
|
||||||
}
|
|
||||||
path.span.hi = self.last_span.hi;
|
|
||||||
|
|
||||||
let hi = self.span.hi;
|
|
||||||
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
|
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
|
||||||
}
|
}
|
||||||
if try!(self.eat_keyword(keywords::Move) ){
|
if try!(self.eat_keyword(keywords::Move) ){
|
||||||
|
@ -3167,16 +3166,25 @@ impl<'a> Parser<'a> {
|
||||||
fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
|
fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
|
||||||
if self.is_path_start() {
|
if self.is_path_start() {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
let path = try!(self.parse_path(LifetimeAndTypesWithColons));
|
let (qself, path) = if try!(self.eat_lt()) {
|
||||||
|
// Parse a qualified path
|
||||||
|
let (qself, path) =
|
||||||
|
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||||
|
(Some(qself), path)
|
||||||
|
} else {
|
||||||
|
// Parse an unqualified path
|
||||||
|
(None, try!(self.parse_path(LifetimeAndTypesWithColons)))
|
||||||
|
};
|
||||||
let hi = self.last_span.hi;
|
let hi = self.last_span.hi;
|
||||||
Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
|
Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
|
||||||
} else {
|
} else {
|
||||||
self.parse_literal_maybe_minus()
|
self.parse_literal_maybe_minus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_path_start(&self) -> bool {
|
fn is_path_start(&self) -> bool {
|
||||||
(self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
|
(self.token == token::Lt || self.token == token::ModSep
|
||||||
|
|| self.token.is_ident() || self.token.is_path())
|
||||||
&& !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
|
&& !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3252,18 +3260,31 @@ impl<'a> Parser<'a> {
|
||||||
pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
|
pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Parse as a general path
|
let (qself, path) = if try!(self.eat_lt()) {
|
||||||
let path = try!(self.parse_path(LifetimeAndTypesWithColons));
|
// Parse a qualified path
|
||||||
|
let (qself, path) =
|
||||||
|
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||||
|
(Some(qself), path)
|
||||||
|
} else {
|
||||||
|
// Parse an unqualified path
|
||||||
|
(None, try!(self.parse_path(LifetimeAndTypesWithColons)))
|
||||||
|
};
|
||||||
match self.token {
|
match self.token {
|
||||||
token::DotDotDot => {
|
token::DotDotDot => {
|
||||||
// Parse range
|
// Parse range
|
||||||
let hi = self.last_span.hi;
|
let hi = self.last_span.hi;
|
||||||
let begin = self.mk_expr(lo, hi, ExprPath(None, path));
|
let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
|
||||||
try!(self.bump());
|
try!(self.bump());
|
||||||
let end = try!(self.parse_pat_range_end());
|
let end = try!(self.parse_pat_range_end());
|
||||||
pat = PatRange(begin, end);
|
pat = PatRange(begin, end);
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Brace) => {
|
token::OpenDelim(token::Brace) => {
|
||||||
|
if qself.is_some() {
|
||||||
|
let span = self.span;
|
||||||
|
self.span_err(span,
|
||||||
|
"unexpected `{` after qualified path");
|
||||||
|
self.abort_if_errors();
|
||||||
|
}
|
||||||
// Parse struct pattern
|
// Parse struct pattern
|
||||||
try!(self.bump());
|
try!(self.bump());
|
||||||
let (fields, etc) = try!(self.parse_pat_fields());
|
let (fields, etc) = try!(self.parse_pat_fields());
|
||||||
|
@ -3271,6 +3292,12 @@ impl<'a> Parser<'a> {
|
||||||
pat = PatStruct(path, fields, etc);
|
pat = PatStruct(path, fields, etc);
|
||||||
}
|
}
|
||||||
token::OpenDelim(token::Paren) => {
|
token::OpenDelim(token::Paren) => {
|
||||||
|
if qself.is_some() {
|
||||||
|
let span = self.span;
|
||||||
|
self.span_err(span,
|
||||||
|
"unexpected `(` after qualified path");
|
||||||
|
self.abort_if_errors();
|
||||||
|
}
|
||||||
// Parse tuple struct or enum pattern
|
// Parse tuple struct or enum pattern
|
||||||
if self.look_ahead(1, |t| *t == token::DotDot) {
|
if self.look_ahead(1, |t| *t == token::DotDot) {
|
||||||
// This is a "top constructor only" pat
|
// This is a "top constructor only" pat
|
||||||
|
@ -3287,6 +3314,10 @@ impl<'a> Parser<'a> {
|
||||||
pat = PatEnum(path, Some(args));
|
pat = PatEnum(path, Some(args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ if qself.is_some() => {
|
||||||
|
// Parse qualified path
|
||||||
|
pat = PatQPath(qself.unwrap(), path);
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Parse nullary enum
|
// Parse nullary enum
|
||||||
pat = PatEnum(path, Some(vec![]));
|
pat = PatEnum(path, Some(vec![]));
|
||||||
|
|
|
@ -2220,6 +2220,9 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::PatQPath(ref qself, ref path) => {
|
||||||
|
try!(self.print_qpath(path, qself, false));
|
||||||
|
}
|
||||||
ast::PatStruct(ref path, ref fields, etc) => {
|
ast::PatStruct(ref path, ref fields, etc) => {
|
||||||
try!(self.print_path(path, true, 0));
|
try!(self.print_path(path, true, 0));
|
||||||
try!(self.nbsp());
|
try!(self.nbsp());
|
||||||
|
|
|
@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatQPath(ref qself, ref path) => {
|
||||||
|
visitor.visit_ty(&qself.ty);
|
||||||
|
visitor.visit_path(path, pattern.id)
|
||||||
|
}
|
||||||
PatStruct(ref path, ref fields, _) => {
|
PatStruct(ref path, ref fields, _) => {
|
||||||
visitor.visit_path(path, pattern.id);
|
visitor.visit_path(path, pattern.id);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
|
35
src/test/compile-fail/method-path-in-pattern.rs
Normal file
35
src/test/compile-fail/method-path-in-pattern.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright 2015 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::marker::MarkerTrait;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn bar(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MyTrait: MarkerTrait {
|
||||||
|
fn trait_bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for Foo {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0u32 {
|
||||||
|
Foo::bar => {} //~ ERROR E0327
|
||||||
|
}
|
||||||
|
match 0u32 {
|
||||||
|
<Foo>::bar => {} //~ ERROR E0327
|
||||||
|
}
|
||||||
|
match 0u32 {
|
||||||
|
<Foo>::trait_bar => {} //~ ERROR E0327
|
||||||
|
}
|
||||||
|
}
|
26
src/test/compile-fail/method-resolvable-path-in-pattern.rs
Normal file
26
src/test/compile-fail/method-resolvable-path-in-pattern.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2015 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::marker::MarkerTrait;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
trait MyTrait: MarkerTrait {
|
||||||
|
fn trait_bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for Foo {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match 0u32 {
|
||||||
|
<Foo as MyTrait>::trait_bar => {}
|
||||||
|
//~^ ERROR `trait_bar` is not an associated const
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/brace-after-qualified-path-in-match.rs
Normal file
17
src/test/parse-fail/brace-after-qualified-path-in-match.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
match x {
|
||||||
|
<T as Trait>::Type{key: value} => (),
|
||||||
|
//~^ ERROR unexpected `{` after qualified path
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
17
src/test/parse-fail/paren-after-qualified-path-in-match.rs
Normal file
17
src/test/parse-fail/paren-after-qualified-path-in-match.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
match x {
|
||||||
|
<T as Trait>::Type(2) => (),
|
||||||
|
//~^ ERROR unexpected `(` after qualified path
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
52
src/test/run-pass/associated-const-match-patterns.rs
Normal file
52
src/test/run-pass/associated-const-match-patterns.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// Copyright 2015 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::marker::MarkerTrait;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
enum Bar {
|
||||||
|
Var1,
|
||||||
|
Var2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use inherent and trait impls to test UFCS syntax.
|
||||||
|
impl Foo {
|
||||||
|
const MYBAR: Bar = Bar::Var2;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait HasBar: MarkerTrait {
|
||||||
|
const THEBAR: Bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasBar for Foo {
|
||||||
|
const THEBAR: Bar = Bar::Var1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Inherent impl
|
||||||
|
assert!(match Bar::Var2 {
|
||||||
|
Foo::MYBAR => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
assert!(match Bar::Var2 {
|
||||||
|
<Foo>::MYBAR => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
// Trait impl
|
||||||
|
assert!(match Bar::Var1 {
|
||||||
|
<Foo>::THEBAR => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
assert!(match Bar::Var1 {
|
||||||
|
<Foo as HasBar>::THEBAR => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue