Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRAM & ANN: Parse parameter attributes and annotate them as experimental #4244

Merged
merged 3 commits into from Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/main/grammars/RustParser.bnf
Expand Up @@ -307,25 +307,27 @@ Lifetime ::= QUOTE_IDENTIFIER {
///////////////////////////////////////////////////////////////////////////////////////////////////

// Parameters
fake ValueParameter ::= Pat? TypeReference? {
fake ValueParameter ::= OuterAttr* Pat? TypeReference? {
implements = [ "org.rust.lang.core.psi.ext.RsOuterAttributeOwner" ]
extends = "org.rust.lang.core.psi.ext.RsStubbedElementImpl<?>"
stubClass = "org.rust.lang.core.stubs.RsValueParameterStub"
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
}

FnParameter ::= !(Pat ':' '...') [ Pat ':' ] TypeReference
FnParameter ::= !(Variadic) OuterAttr* [ Pat ':' ] TypeReference
private FnParameter_with_recover ::= FnParameter (',' | &')') {
pin = 1
recoverWhile = FnParameter_recover
}
private FnParameter_recover ::= !(Pat_first | ')' | '...')
private FnParameter_recover ::= !(Pat_first | OuterAttr_first | ')' | '...')

LambdaParameter ::= Pat TypeAscription?
AnonParameter ::= [ RestrictedPat ':' ] TypeReference
PathParameter ::= TypeReference !'='
LambdaParameter ::= OuterAttr* Pat TypeAscription?
AnonParameter ::= OuterAttr* [ RestrictedPat ':' ] TypeReference
PathParameter ::= OuterAttr* TypeReference !'='

SelfParameter ::= [ '&' Lifetime? ] mut? self TypeAscription? {
implements = [ "org.rust.lang.core.psi.ext.RsNameIdentifierOwner" ]
SelfParameter ::= OuterAttr* [ '&' Lifetime? ] mut? self TypeAscription? {
implements = [ "org.rust.lang.core.psi.ext.RsNameIdentifierOwner"
"org.rust.lang.core.psi.ext.RsOuterAttributeOwner" ]
mixin = "org.rust.lang.core.psi.ext.RsSelfParameterImplMixin"
stubClass = "org.rust.lang.core.stubs.RsSelfParameterStub"
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
Expand All @@ -350,7 +352,12 @@ private meta variadic_params_impl ::= '(' [ <<param>> (',' <<param>>)* [ ',' '.

private RestrictedPat ::= &( [ mut | '&' '&'? ] ( identifier | '_' ) ) Pat

Variadic ::= [ Pat ':' ] '...'
Variadic ::= OuterAttr* [ Pat ':' ] '...' {
implements = [ "org.rust.lang.core.psi.ext.RsOuterAttributeOwner" ]
extends = "org.rust.lang.core.psi.ext.RsStubbedElementImpl<?>"
stubClass = "org.rust.lang.core.stubs.RsPlaceholderStub"
elementTypeFactory = "org.rust.lang.core.stubs.StubImplementationsKt.factory"
}

TypeParameterList ::= '<' <<list_element (LifetimeParameter | TypeParameter | ConstParameter)>>* '>' {
extends = "org.rust.lang.core.psi.ext.RsStubbedElementImpl<?>"
Expand Down
26 changes: 21 additions & 5 deletions src/main/kotlin/org/rust/ide/annotator/RsErrorAnnotator.kt
Expand Up @@ -27,12 +27,8 @@ import org.rust.lang.core.resolve.Namespace
import org.rust.lang.core.resolve.knownItems
import org.rust.lang.core.resolve.namespaces
import org.rust.lang.core.resolve.ref.deepResolve
import org.rust.lang.core.types.TraitRef
import org.rust.lang.core.types.implLookup
import org.rust.lang.core.types.asTy
import org.rust.lang.core.types.inference
import org.rust.lang.core.types.*
import org.rust.lang.core.types.ty.*
import org.rust.lang.core.types.type
import org.rust.lang.utils.RsDiagnostic
import org.rust.lang.utils.RsErrorCode
import org.rust.lang.utils.addToHolder
Expand Down Expand Up @@ -86,6 +82,9 @@ class RsErrorAnnotator : RsAnnotatorBase(), HighlightRangeExtension {
override fun visitAttr(o: RsAttr) = checkAttr(holder, o)
override fun visitRangeExpr(o: RsRangeExpr) = checkRangeExpr(holder, o)
override fun visitTraitType(o: RsTraitType) = checkTraitType(holder, o)
override fun visitSelfParameter(o: RsSelfParameter) = checkParamAttrs(holder, o)
override fun visitValueParameter(o: RsValueParameter) = checkParamAttrs(holder, o)
override fun visitVariadic(o: RsVariadic) = checkParamAttrs(holder, o)
}

element.accept(visitor)
Expand Down Expand Up @@ -797,6 +796,23 @@ private fun checkDuplicates(holder: AnnotationHolder, element: RsNameIdentifierO
message.addToHolder(holder)
}

private fun checkParamAttrs(holder: AnnotationHolder, o: RsOuterAttributeOwner) {
val outerAttrs = o.outerAttrList
if (outerAttrs.isEmpty()) return
val startElement = outerAttrs.first()
val endElement = outerAttrs.last()
val message = "attributes on function parameters is experimental"
val diagnostic = when (PARAM_ATTRS.availability(startElement)) {
NOT_AVAILABLE -> RsDiagnostic.ExperimentalFeature(startElement, endElement, message, emptyList())
CAN_BE_ADDED -> {
val fix = PARAM_ATTRS.addFeatureFix(startElement)
RsDiagnostic.ExperimentalFeature(startElement, endElement, message, listOf(fix))
}
else -> return
}
diagnostic.addToHolder(holder)
}

private fun AnnotationSession.duplicatesByNamespace(owner: PsiElement, recursively: Boolean): Map<Namespace, Set<PsiElement>> {
if (owner.parent is RsFnPointerType) return emptyMap()

Expand Down
53 changes: 24 additions & 29 deletions src/main/kotlin/org/rust/lang/core/CompilerFeatures.kt
Expand Up @@ -16,6 +16,8 @@ import org.rust.lang.core.FeatureState.ACTIVE

// no-tracking-issue-start

// Allows using compiler's own crates.
val RUSTC_PRIVATE = CompilerFeature("rustc_private", ACTIVE, "1.0.0")
// Allows using the `rust-intrinsic`'s "ABI".
val INTRINSICS = CompilerFeature("intrinsics", ACTIVE, "1.0.0")
// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
Expand Down Expand Up @@ -70,8 +72,6 @@ val BOX_PATTERNS = CompilerFeature("box_patterns", ACTIVE, "1.0.0")
val PRELUDE_IMPORT = CompilerFeature("prelude_import", ACTIVE, "1.2.0")
// no-tracking-issue-end

// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
val DROPCK_PARAMETRICITY = CompilerFeature("dropck_parametricity", ACTIVE, "1.3.0")
// no-tracking-issue-start

// Allows using `#[omit_gdb_pretty_printer_section]`.
Expand Down Expand Up @@ -102,8 +102,6 @@ val PROFILER_RUNTIME = CompilerFeature("profiler_runtime", ACTIVE, "1.18.0")
val ABI_THISCALL = CompilerFeature("abi_thiscall", ACTIVE, "1.19.0")
// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
val ALLOCATOR_INTERNALS = CompilerFeature("allocator_internals", ACTIVE, "1.20.0")
// Allows using the `format_args_nl` macro.
val FORMAT_ARGS_NL = CompilerFeature("format_args_nl", ACTIVE, "1.29.0")
// no-tracking-issue-end

// Added for testing E0705; perma-unstable.
Expand Down Expand Up @@ -142,10 +140,6 @@ val F16C_TARGET_FEATURE = CompilerFeature("f16c_target_feature", ACTIVE, "1.36.0
// feature-group-start: actual feature gates
// -------------------------------------------------------------------------

// Allows using `asm!` macro with which inline assembly can be embedded.
val ASM = CompilerFeature("asm", ACTIVE, "1.0.0")
// Allows using the `concat_idents!` macro with which identifiers can be concatenated.
val CONCAT_IDENTS = CompilerFeature("concat_idents", ACTIVE, "1.0.0")
// Allows using the `#[link_args]` attribute.
val LINK_ARGS = CompilerFeature("link_args", ACTIVE, "1.0.0")
// Allows defining identifiers beyond ASCII.
Expand All @@ -156,10 +150,6 @@ val PLUGIN_REGISTRAR = CompilerFeature("plugin_registrar", ACTIVE, "1.0.0")
val PLUGIN = CompilerFeature("plugin", ACTIVE, "1.0.0")
// Allows using `#[thread_local]` on `static` items.
val THREAD_LOCAL = CompilerFeature("thread_local", ACTIVE, "1.0.0")
// Allows using the `log_syntax!` macro.
val LOG_SYNTAX = CompilerFeature("log_syntax", ACTIVE, "1.0.0")
// Allows using the `trace_macros!` macro.
val TRACE_MACROS = CompilerFeature("trace_macros", ACTIVE, "1.0.0")
// Allows the use of SIMD types in functions declared in `extern` blocks.
val SIMD_FFI = CompilerFeature("simd_ffi", ACTIVE, "1.0.0")
// Allows using custom attributes (RFC 572).
Expand Down Expand Up @@ -220,8 +210,6 @@ val ABI_MSP430_INTERRUPT = CompilerFeature("abi_msp430_interrupt", ACTIVE, "1.16
val DECL_MACRO = CompilerFeature("decl_macro", ACTIVE, "1.17.0")
// Allows `extern "x86-interrupt" fn()`.
val ABI_X86_INTERRUPT = CompilerFeature("abi_x86_interrupt", ACTIVE, "1.17.0")
// Allows module-level inline assembly by way of `global_asm!()`.
val GLOBAL_ASM = CompilerFeature("global_asm", ACTIVE, "1.18.0")
// Allows overlapping impls of marker traits.
val OVERLAPPING_MARKER_TRAITS = CompilerFeature("overlapping_marker_traits", ACTIVE, "1.18.0")
// Allows a test to fail without failing the whole suite.
Expand Down Expand Up @@ -266,8 +254,6 @@ val CONST_RAW_PTR_DEREF = CompilerFeature("const_raw_ptr_deref", ACTIVE, "1.27.0
val CONST_COMPARE_RAW_POINTERS = CompilerFeature("const_compare_raw_pointers", ACTIVE, "1.27.0")
// Allows `#[doc(alias = "...")]`.
val DOC_ALIAS = CompilerFeature("doc_alias", ACTIVE, "1.27.0")
// Allows defining `existential type`s.
val EXISTENTIAL_TYPE = CompilerFeature("existential_type", ACTIVE, "1.28.0")
// Allows inconsistent bounds in where clauses.
val TRIVIAL_BOUNDS = CompilerFeature("trivial_bounds", ACTIVE, "1.28.0")
// Allows `'a: { break 'a; }`.
Expand All @@ -276,9 +262,6 @@ val LABEL_BREAK_VALUE = CompilerFeature("label_break_value", ACTIVE, "1.28.0")
val DOC_KEYWORD = CompilerFeature("doc_keyword", ACTIVE, "1.28.0")
// Allows async and await syntax.
val ASYNC_AWAIT = CompilerFeature("async_await", ACTIVE, "1.28.0")
// Allows await! macro-like syntax.
// This will likely be removed prior to stabilization of async/await.
val AWAIT_MACRO = CompilerFeature("await_macro", ACTIVE, "1.28.0")
// Allows reinterpretation of the bits of a value of one type as another type during const eval.
val CONST_TRANSMUTE = CompilerFeature("const_transmute", ACTIVE, "1.29.0")
// Allows using `try {...}` expressions.
Expand All @@ -304,12 +287,8 @@ val CUSTOM_INNER_ATTRIBUTES = CompilerFeature("custom_inner_attributes", ACTIVE,
val BIND_BY_MOVE_PATTERN_GUARDS = CompilerFeature("bind_by_move_pattern_guards", ACTIVE, "1.30.0")
// Allows `impl Trait` in bindings (`let`, `const`, `static`).
val IMPL_TRAIT_IN_BINDINGS = CompilerFeature("impl_trait_in_bindings", ACTIVE, "1.30.0")
// Allows `const _: TYPE = VALUE`.
val UNDERSCORE_CONST_NAMES = CompilerFeature("underscore_const_names", ACTIVE, "1.31.0")
// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
val LINT_REASONS = CompilerFeature("lint_reasons", ACTIVE, "1.31.0")
// Allows paths to enum variants on type aliases.
val TYPE_ALIAS_ENUM_VARIANTS = CompilerFeature("type_alias_enum_variants", ACTIVE, "1.31.0")
// Allows exhaustive integer pattern matching on `usize` and `isize`.
val PRECISE_POINTER_SIZE_MATCHING = CompilerFeature("precise_pointer_size_matching", ACTIVE, "1.32.0")
// Allows relaxing the coherence rules such that
Expand All @@ -321,23 +300,32 @@ val FFI_RETURNS_TWICE = CompilerFeature("ffi_returns_twice", ACTIVE, "1.34.0")
val CONST_GENERICS = CompilerFeature("const_generics", ACTIVE, "1.34.0")
// Allows using `#[optimize(X)]`.
val OPTIMIZE_ATTRIBUTE = CompilerFeature("optimize_attribute", ACTIVE, "1.34.0")
// Allows using `#[repr(align(X))]` on enums.
val REPR_ALIGN_ENUM = CompilerFeature("repr_align_enum", ACTIVE, "1.34.0")
// Allows using C-variadics.
val C_VARIADIC = CompilerFeature("c_variadic", ACTIVE, "1.34.0")
// Allows the user of associated type bounds.
val ASSOCIATED_TYPE_BOUNDS = CompilerFeature("associated_type_bounds", ACTIVE, "1.34.0")
// Allows calling constructor functions in `const fn`
// FIXME Create issue
// Attributes on formal function params.
val PARAM_ATTRS = CompilerFeature("param_attrs", ACTIVE, "1.36.0")
// Allows calling constructor functions in `const fn`.
val CONST_CONSTRUCTOR = CompilerFeature("const_constructor", ACTIVE, "1.37.0")
// Allows `if/while p && let q = r && ...` chains.
val LET_CHAINS = CompilerFeature("let_chains", ACTIVE, "1.37.0")
// #[repr(transparent)] on enums.
// Allows #[repr(transparent)] on enums (RFC 2645).
val TRANSPARENT_ENUMS = CompilerFeature("transparent_enums", ACTIVE, "1.37.0")
// #[repr(transparent)] on unions.
// Allows #[repr(transparent)] on unions (RFC 2645).
val TRANSPARENT_UNIONS = CompilerFeature("transparent_unions", ACTIVE, "1.37.0")
// Allows explicit discriminants on non-unit enum variants.
val ARBITRARY_ENUM_DISCRIMINANT = CompilerFeature("arbitrary_enum_discriminant", ACTIVE, "1.37.0")
// Allows `impl Trait` with multiple unrelated lifetimes.
val MEMBER_CONSTRAINTS = CompilerFeature("member_constraints", ACTIVE, "1.37.0")
// Allows `async || body` closures.
val ASYNC_CLOSURE = CompilerFeature("async_closure", ACTIVE, "1.37.0")
// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests
val CFG_DOCTEST = CompilerFeature("cfg_doctest", ACTIVE, "1.37.0")
// Allows `[x; N]` where `x` is a constant (RFC 2203).
val CONST_IN_ARRAY_REPEAT_EXPRESSIONS = CompilerFeature("const_in_array_repeat_expressions", ACTIVE, "1.37.0")
// Allows `impl Trait` to be used inside type aliases (RFC 2515).
val TYPE_ALIAS_IMPL_TRAIT = CompilerFeature("type_alias_impl_trait", ACTIVE, "1.38.0")

// -------------------------------------------------------------------------
// feature-group-start: for testing purposes
Expand Down Expand Up @@ -546,3 +534,10 @@ val CFG_TARGET_VENDOR = CompilerFeature("cfg_target_vendor", ACCEPTED, "1.33.0")
val EXTERN_CRATE_SELF = CompilerFeature("extern_crate_self", ACCEPTED, "1.34.0")
// Allows arbitrary delimited token streams in non-macro attributes.
val UNRESTRICTED_ATTRIBUTE_TOKENS = CompilerFeature("unrestricted_attribute_tokens", ACCEPTED, "1.34.0")
// Allows paths to enum variants on type aliases including `Self`.
val TYPE_ALIAS_ENUM_VARIANTS = CompilerFeature("type_alias_enum_variants", ACCEPTED, "1.37.0")
// Allows using `#[repr(align(X))]` on enums with equivalent semantics
// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`.
val REPR_ALIGN_ENUM = CompilerFeature("repr_align_enum", ACCEPTED, "1.37.0")
// Allows `const _: TYPE = VALUE`.
val UNDERSCORE_CONST_NAMES = CompilerFeature("underscore_const_names", ACCEPTED, "1.37.0")
Expand Up @@ -36,7 +36,7 @@ class RsFileStub : PsiFileStubImpl<RsFile> {

object Type : IStubFileElementType<RsFileStub>(RsLanguage) {
// Bump this number if Stub structure changes
override fun getStubVersion(): Int = 178
override fun getStubVersion(): Int = 179

override fun getBuilder(): StubBuilder = object : DefaultStubBuilder() {
override fun createStubForFile(file: PsiFile): StubElement<*> = RsFileStub(file as RsFile)
Expand Down Expand Up @@ -122,6 +122,7 @@ fun factory(name: String): RsStubElementType<*, *> = when (name) {
"VALUE_PARAMETER_LIST" -> RsPlaceholderStub.Type("VALUE_PARAMETER_LIST", ::RsValueParameterListImpl)
"VALUE_PARAMETER" -> RsValueParameterStub.Type
"SELF_PARAMETER" -> RsSelfParameterStub.Type
"VARIADIC" -> RsPlaceholderStub.Type("VARIADIC", ::RsVariadicImpl)
"TYPE_PARAMETER_LIST" -> RsPlaceholderStub.Type("TYPE_PARAMETER_LIST", ::RsTypeParameterListImpl)
"TYPE_PARAMETER" -> RsTypeParameterStub.Type
"CONST_PARAMETER" -> RsConstParameterStub.Type
Expand Down
37 changes: 37 additions & 0 deletions src/test/kotlin/org/rust/ide/annotator/RsErrorAnnotatorTest.kt
Expand Up @@ -2721,4 +2721,41 @@ class RsErrorAnnotatorTest : RsAnnotatorTestBase(RsErrorAnnotator::class.java) {
};
}
""")

@MockRustcVersion("1.35.0")
fun `test param attrs E0658 1`() = checkErrors("""
struct S;
fn f1(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> x: S) {}
fn f2(<error descr="attributes on function parameters is experimental [E0658]">#[attr1] #[attr2]</error> x: S) {}
impl S {
fn f3(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> self) {}
fn f4(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> &self) {}
fn f5<'a>(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> &mut self) {}
fn f6<'a>(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> &'a self) {}
fn f7<'a>(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> &'a mut self, <error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> x: S, y: S) {}
fn f8(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> self: Self) {}
fn f9(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> self: S<Self>) {}
}
trait T { fn f10(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> S); }
extern "C" { fn f11(<error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> x: S, <error descr="attributes on function parameters is experimental [E0658]">#[attr]</error> ...); }
""")

@MockRustcVersion("1.36.0-nightly")
fun `test param attrs E0658 2`() = checkErrors("""
#![feature(param_attrs)]
struct S;
fn f1(#[attr] x: S) {}
fn f2(#[attr1] #[attr2] x: S) {}
impl S {
fn f3(#[attr] self) {}
fn f4(#[attr] &self) {}
fn f5<'a>(#[attr] &mut self) {}
fn f6<'a>(#[attr] &'a self) {}
fn f7<'a>(#[attr] &'a mut self, #[attr] x: S, y: S) {}
fn f8(#[attr] self: Self) {}
fn f9(#[attr] self: S<Self>) {}
}
trait T { fn f10(#[attr] S); }
extern "C" { fn f11(#[attr] x: S, #[attr] ...); }
""")
}
Expand Up @@ -55,6 +55,7 @@ class RsCompleteParsingTestCase : RsParsingTestCaseBase("complete") {
fun `test diesel macros`() = doTest(true)

fun `test attrs in exprs`() = doTest(true)
fun `test attrs in params`() = doTest(true)

override fun checkResult(targetDataName: String, file: PsiFile) {
super.checkResult(targetDataName, file)
Expand Down
@@ -0,0 +1,25 @@
fn f1(#[attr1] #[attr2] pat: S) {}

fn f2(#[attr] x: S) {}

impl S {
fn f3(#[attr] self) {}

fn f4(#[attr] &self) {}

fn f5<'a>(#[attr] &mut self) {}

fn f6<'a>(#[attr] &'a self) {}

fn f7<'a>(#[attr] &'a mut self, #[attr] x: S, y: S) {}

fn f8(#[attr] self: Self) {}

fn f9(#[attr] self: S<Self>) {}
}

trait T { fn f10(#[attr] S); }

extern "C" {
fn f11(#[attr] x: S, #[attr] ...);
}