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

Introduce EDITION_2021 #6903

Merged
merged 1 commit into from Apr 14, 2021
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
Expand Up @@ -201,7 +201,9 @@ interface CargoWorkspace {
}

enum class Edition(val presentation: String) {
EDITION_2015("2015"), EDITION_2018("2018")
EDITION_2015("2015"),
EDITION_2018("2018"),
EDITION_2021("2021")
}

companion object {
Expand Down
Expand Up @@ -515,6 +515,7 @@ object CargoMetadata {
private fun String?.cleanEdition(): Edition = when (this) {
Edition.EDITION_2015.presentation -> Edition.EDITION_2015
Edition.EDITION_2018.presentation -> Edition.EDITION_2018
Edition.EDITION_2021.presentation -> Edition.EDITION_2021
else -> Edition.EDITION_2015
}

Expand Down
Expand Up @@ -12,7 +12,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapiext.isUnitTestMode
import com.intellij.psi.PsiElement
import org.rust.cargo.project.workspace.CargoWorkspace
import org.rust.ide.colors.RsColor
import org.rust.ide.utils.isEnabledByCfg
import org.rust.lang.core.psi.*
Expand All @@ -21,26 +20,26 @@ import org.rust.lang.core.psi.ext.*

class RsEdition2018KeywordsAnnotator : AnnotatorBase() {
override fun annotateInternal(element: PsiElement, holder: AnnotationHolder) {
val edition = element.edition ?: return
if (element.edition == null) return

if (!isEdition2018Keyword(element)) return

val isEdition2018 = edition == CargoWorkspace.Edition.EDITION_2018
val isAtLeastEdition2018 = element.isAtLeastEdition2018
val isIdentifier = element.elementType == IDENTIFIER
val isEnabledByCfg = element.isEnabledByCfg
when {
isEdition2018 && isIdentifier && isNameIdentifier(element) ->
isAtLeastEdition2018 && isIdentifier && isNameIdentifier(element) ->
holder.newAnnotation(HighlightSeverity.ERROR, "`${element.text}` is reserved keyword in Edition 2018").create()

isEdition2018 && !isIdentifier && isEnabledByCfg -> {
isAtLeastEdition2018 && !isIdentifier && isEnabledByCfg -> {
if (!holder.isBatchMode) {
val severity = if (isUnitTestMode) RsColor.KEYWORD.testSeverity else HighlightSeverity.INFORMATION
holder.newSilentAnnotation(severity)
.textAttributes(RsColor.KEYWORD.textAttributesKey).create()
}
}

isEdition2018 && !isIdentifier && !isEnabledByCfg -> {
isAtLeastEdition2018 && !isIdentifier && !isEnabledByCfg -> {
if (!holder.isBatchMode) {
val colorScheme = EditorColorsManager.getInstance().globalScheme
val keywordTextAttributes = colorScheme.getAttributes(RsColor.KEYWORD.textAttributesKey)
Expand All @@ -52,7 +51,7 @@ class RsEdition2018KeywordsAnnotator : AnnotatorBase() {
}
}

!isEdition2018 && !isIdentifier ->
!isAtLeastEdition2018 && !isIdentifier ->
holder.newAnnotation(HighlightSeverity.ERROR, "This feature is only available in Edition 2018").create()
}
}
Expand Down
Expand Up @@ -116,7 +116,7 @@ class RsHighlightingAnnotator : AnnotatorBase() {
isPrimitiveType -> RsColor.PRIMITIVE_TYPE
parent is RsMacroCall -> if (shouldHighlightMacroCall(parent, holder)) RsColor.MACRO else null
element is RsMethodCall -> RsColor.METHOD_CALL
element is RsFieldLookup && element.identifier?.text == "await" && element.isEdition2018 -> RsColor.KEYWORD
element is RsFieldLookup && element.identifier?.text == "await" && element.isAtLeastEdition2018 -> RsColor.KEYWORD
element is RsPath && element.isCall() -> {
val ref = reference?.resolve() ?: return null
if (ref is RsFunction) {
Expand Down
Expand Up @@ -91,7 +91,7 @@ class AttachFileToModuleFix(
modules.addIfNotNull(findModule(file, project, directory.findFileByRelativePath(RsConstants.MOD_RS_FILE)))

// module file in parent directory
if (pkg.edition == CargoWorkspace.Edition.EDITION_2018) {
if (pkg.edition >= CargoWorkspace.Edition.EDITION_2018) {
modules.addIfNotNull(findModule(file, project, directory.parent?.findFileByRelativePath("${directory.name}.rs")))
}

Expand Down
Expand Up @@ -12,7 +12,7 @@ import com.intellij.psi.PsiElement
import org.rust.ide.inspections.RsProblemsHolder
import org.rust.lang.core.psi.*
import org.rust.lang.core.psi.ext.dyn
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.lang.core.psi.ext.skipParens
import org.rust.lang.core.resolve.ref.deepResolve

Expand All @@ -22,7 +22,7 @@ class RsBareTraitObjectsInspection : RsLintInspection() {
override fun buildVisitor(holder: RsProblemsHolder, isOnTheFly: Boolean): RsVisitor =
object : RsVisitor() {
override fun visitTypeReference(typeReference: RsTypeReference) {
if (!typeReference.isEdition2018) return
if (!typeReference.isAtLeastEdition2018) return

val traitType = typeReference.skipParens() as? RsTraitType
val baseTypePath = (typeReference.skipParens() as? RsBaseType)?.path
Expand Down
Expand Up @@ -38,7 +38,7 @@ class CreateFunctionIntention : RsElementBaseIntentionAction<CreateFunctionInten

sealed class Context(val name: String, val callElement: PsiElement) {
abstract val visibility: String
open val isAsync: Boolean = callElement.isEdition2018
open val isAsync: Boolean = callElement.isAtLeastEdition2018
abstract val arguments: RsValueArgumentList
abstract val returnType: Ty?
open val implItem: RsImplItem? = null
Expand Down
Expand Up @@ -20,7 +20,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori
import com.intellij.refactoring.util.CommonRefactoringUtil
import org.rust.lang.RsLanguage
import org.rust.lang.core.psi.RsFile
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.stdext.mapToSet

class RsMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandler() {
Expand Down Expand Up @@ -118,5 +118,5 @@ private fun RsFile.canBeMoved(): Boolean =
&& crateRoot != null
&& crateRelativePath != null
&& !isCrateRoot
&& isEdition2018 // TODO: support 2015 edition
&& isAtLeastEdition2018 // TODO: support 2015 edition
&& pathAttribute == null // TODO: support path attribute on mod declaration
Expand Up @@ -191,7 +191,7 @@ object ImportCandidatesCollector {
ourSuperMods to importInfo
} else {
val targetMod = superMods.first()
val relativePath = if (targetMod.isEdition2018) {
val relativePath = if (targetMod.isAtLeastEdition2018) {
"crate::$crateRelativePath"
} else {
crateRelativePath
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/org/rust/ide/utils/import/importUtils.kt
Expand Up @@ -25,7 +25,7 @@ fun ImportCandidate.import(context: RsElement) {
// we uses this info to create correct relative use item path if needed
var relativeDepth: Int? = null

val isEdition2018 = context.isEdition2018
val isAtLeastEdition2018 = context.isAtLeastEdition2018
val info = info
// if crate of importing element differs from current crate
// we need to add new extern crate item
Expand All @@ -42,7 +42,7 @@ fun ImportCandidate.import(context: RsElement) {
// we don't add corresponding extern crate item manually for the same reason
attributes == RsFile.Attributes.NO_STD && crate.isCore -> Testmarks.autoInjectedCoreCrate.hit()
else -> {
if (info.needInsertExternCrateItem && !isEdition2018) {
if (info.needInsertExternCrateItem && !isAtLeastEdition2018) {
crateRoot?.insertExternCrateItem(psiFactory, info.externCrateName)
} else {
if (info.depth != null) {
Expand Down
Expand Up @@ -17,7 +17,7 @@ import com.intellij.util.ProcessingContext
import org.rust.lang.core.psi.RsElementTypes
import org.rust.lang.core.psi.RsFieldLookup
import org.rust.lang.core.psi.ext.findAssociatedType
import org.rust.lang.core.psi.ext.isEdition2018
import org.rust.lang.core.psi.ext.isAtLeastEdition2018
import org.rust.lang.core.psi.ext.receiver
import org.rust.lang.core.psi.ext.withSubst
import org.rust.lang.core.psiElement
Expand All @@ -36,7 +36,7 @@ object RsAwaitCompletionProvider : RsCompletionProvider() {
val parent = psiElement<RsFieldLookup>()
.with(object : PatternCondition<RsFieldLookup>("RsPostfixAwait") {
override fun accepts(t: RsFieldLookup, context: ProcessingContext?): Boolean {
if (context == null || !t.isEdition2018) return false
if (context == null || !t.isAtLeastEdition2018) return false
val receiver = t.receiver.safeGetOriginalOrSelf()
val lookup = ImplLookup.relativeTo(receiver)
val awaitTy = receiver.type.lookupFutureOutputTy(lookup)
Expand Down
7 changes: 5 additions & 2 deletions src/main/kotlin/org/rust/lang/core/psi/ext/RsElement.kt
Expand Up @@ -65,8 +65,11 @@ val RsElement.containingCargoPackage: CargoWorkspace.Package? get() = containing
val PsiElement.edition: CargoWorkspace.Edition?
get() = contextOrSelf<RsElement>()?.containingCrate?.edition

val PsiElement.isEdition2018: Boolean
get() = edition == CargoWorkspace.Edition.EDITION_2018
val PsiElement.isAtLeastEdition2018: Boolean
get() {
val edition = edition ?: return false
return edition >= CargoWorkspace.Edition.EDITION_2018
}

/**
* It is possible to match value with constant-like element, e.g.
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/org/rust/lang/core/resolve/ItemResolution.kt
Expand Up @@ -110,12 +110,12 @@ fun processItemDeclarations(
}
}

val isEdition2018 = scope.isEdition2018
val isAtLeastEdition2018 = scope.isAtLeastEdition2018
for ((isPublic, path, name, isAtom) in cachedItems.namedImports) {
if (!(isPublic || withPrivateImports)) continue

if (isEdition2018 && isAtom) {
// Use items like `use foo;` or `use foo::{self}` are meaningful on 2018 edition
if (isAtLeastEdition2018 && isAtom) {
// Use items like `use foo;` or `use foo::{self}` are meaningful since 2018 edition
// only if `foo` is a crate, and it is `pub use` item. Otherwise,
// we should ignore it or it breaks resolve of such `foo` in other places.
ItemResolutionTestmarks.extraAtomUse.hit()
Expand All @@ -131,7 +131,7 @@ fun processItemDeclarations(
}
}

if (withPrivateImports && Namespace.Types in ns && scope is RsFile && !isEdition2018 && scope.isCrateRoot) {
if (withPrivateImports && Namespace.Types in ns && scope is RsFile && !isAtLeastEdition2018 && scope.isCrateRoot) {
// Rust injects implicit `extern crate std` in every crate root module unless it is
// a `#![no_std]` crate, in which case `extern crate core` is injected. However, if
// there is a (unstable?) `#![no_core]` attribute, nothing is injected.
Expand All @@ -154,7 +154,7 @@ fun processItemDeclarations(
}

if (ipm.withExternCrates && Namespace.Types in ns && scope is RsMod) {
if (isEdition2018 && !scope.isCrateRoot) {
if (isAtLeastEdition2018 && !scope.isCrateRoot) {
val crateRoot = scope.crateRoot
if (crateRoot != null) {
val result = processWithShadowingAndUpdateScope(directlyDeclaredNames, originalProcessor) { shadowingProcessor ->
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
Expand Up @@ -554,7 +554,7 @@ private fun processUnqualifiedPathResolveVariants(
}
}

val isEdition2018 = (crateRoot ?: containingMod).isEdition2018
val isAtLeastEdition2018 = (crateRoot ?: containingMod).isAtLeastEdition2018

// In 2015 edition a path is crate-relative (global) if it's inside use item,
// inside "visibility restriction" or if it starts with `::`
Expand All @@ -564,13 +564,13 @@ private fun processUnqualifiedPathResolveVariants(
// pub(in foo::bar) fn baz() {}
// //^ crate-relative path too
// ```
// In 2018 edition a path is crate-relative if it starts with `crate::` (handled above)
// or if it's inside "visibility restriction". `::`-qualified path on 2018 edition means that
// Starting 2018 edition a path is crate-relative if it starts with `crate::` (handled above)
// or if it's inside "visibility restriction". `::`-qualified path since 2018 edition means that
// such path is a name of some dependency crate (that should be resolved without `extern crate`)
val isCrateRelative = !isEdition2018 && (hasColonColon || path.rootPath().parent is RsUseSpeck)
val isCrateRelative = !isAtLeastEdition2018 && (hasColonColon || path.rootPath().parent is RsUseSpeck)
|| path.rootPath().parent is RsVisRestriction
// see https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#the-crate-keyword-refers-to-the-current-crate
val isExternCrate = isEdition2018 && hasColonColon
val isExternCrate = isAtLeastEdition2018 && hasColonColon
return when {
isCrateRelative -> if (crateRoot != null) {
processItemOrEnumVariantDeclarations(crateRoot, ns, processor, withPrivateImports = { true })
Expand Down
Expand Up @@ -123,7 +123,7 @@ class RsPathReferenceImpl(
}

private fun bindToMod(target: RsMod): PsiElement? {
if (!element.isEdition2018) return null
if (!element.isAtLeastEdition2018) return null
var targetPath = target.qualifiedNameRelativeTo(element.containingMod) ?: return null

// consider old target (`element.reference.resolve()`) was `bar1::bar2::bar3::bar4::foo`
Expand Down
Expand Up @@ -792,7 +792,7 @@ class RsTypeInferenceWalker(
}

private fun inferFieldExprType(receiver: Ty, fieldLookup: RsFieldLookup): Ty {
if (fieldLookup.identifier?.text == "await" && fieldLookup.isEdition2018) {
if (fieldLookup.identifier?.text == "await" && fieldLookup.isAtLeastEdition2018) {
return receiver.lookupFutureOutputTy(lookup)
}

Expand Down