Skip to content

Commit 2c19b68

Browse files
bors[bot]Undin
andauthored
Merge #9480
9480: Convert compiler features to json and update compiler features r=mchernyavsky a=Undin After rust-lang/rust#100591, compiler uses `CURRENT_RUSTC_VERSION` placeholder as value of `since` field which means that feature is available in the current compiler. It's ok for the compiler, but the plugin should work with different compiler versions, so it needs some concrete version when the feature became available to annotate code properly. The main idea to solve this problem is to use already saved values: - if feature has a placeholder and we didn't meet it before, the current compiler version will be used to replace the placeholder. Here we assume that this code is launched with the same (or almost the same) rustc version as in rustc master - otherwise, just use version saved previously Previously, we saved info about compiler features directly as generated kotlin code and it made loading this info from `attributes-info` quite complicated. So, now compiler features are saved in language independent form - json file located in resources. This approach not only allows us to deserialize data in any language. It also opens up the possibility to upload generated json somewhere and load this file from plugin to update features info Closes #9258 changelog: Keep info about compiler features in json instead of generated Kotlin code Co-authored-by: Arseniy Pendryak <[email protected]>
2 parents 85158ea + 17060a1 commit 2c19b68

File tree

17 files changed

+678
-504
lines changed

17 files changed

+678
-504
lines changed

attributes-info/Cargo.lock

Lines changed: 25 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

attributes-info/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ edition = "2021"
55

66
[dependencies]
77
rustc_feature = { path = "rustc_feature" }
8+
serde = { version = "1.0", features = ["derive"] }
9+
serde_json = "1.0"
10+
version_check = "0.9.4"
811

912
[workspace]
1013
members = [

attributes-info/rustc_feature/build.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ use std::{env, fs};
22
use std::path::Path;
33

44
use reqwest::blocking::get;
5+
use reqwest::IntoUrl;
56

67
fn main() {
7-
download_file("https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/active.rs", "active.rs");
8-
download_file("https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/accepted.rs", "accepted.rs");
9-
download_file("https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/removed.rs", "removed.rs");
10-
download_file("https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/builtin_attrs.rs", "builtin_attrs.rs");
8+
let commit = env::var("RUSTC_COMMIT").unwrap_or(String::from("master"));
9+
10+
download_file(format!("https://raw.githubusercontent.com/rust-lang/rust/{commit}/compiler/rustc_feature/src/active.rs"), "active.rs");
11+
download_file(format!("https://raw.githubusercontent.com/rust-lang/rust/{commit}/compiler/rustc_feature/src/accepted.rs"), "accepted.rs");
12+
download_file(format!("https://raw.githubusercontent.com/rust-lang/rust/{commit}/compiler/rustc_feature/src/removed.rs"), "removed.rs");
13+
download_file(format!("https://raw.githubusercontent.com/rust-lang/rust/{commit}/compiler/rustc_feature/src/builtin_attrs.rs"), "builtin_attrs.rs");
1114
}
1215

13-
fn download_file(url: &str, file_name: &str) {
16+
fn download_file<T: IntoUrl>(url: T, file_name: &str) {
1417
let text = get(url)
1518
.unwrap()
1619
.text()

attributes-info/rustc_span/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use reqwest::blocking::get;
55
use syn::{File, Item};
66

77
fn main() {
8-
let text = get("https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_span/src/symbol.rs")
8+
let commit = env::var("RUSTC_COMMIT").unwrap_or(String::from("master"));
9+
let text = get(format!("https://raw.githubusercontent.com/rust-lang/rust/{commit}/compiler/rustc_span/src/symbol.rs"))
910
.unwrap()
1011
.text()
1112
.unwrap();

attributes-info/src/main.rs

Lines changed: 99 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,119 @@
1+
use std::collections::HashMap;
12
use std::fs::File;
3+
use std::io;
24
use std::io::Write;
3-
use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, Feature, Features, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, State};
45

5-
fn main() {
6-
let mut f = File::create("src/main/kotlin/org/rust/lang/core/CompilerFeatures.kt").unwrap();
6+
use serde::{Deserialize, Serialize, Serializer};
7+
use serde::ser::SerializeSeq;
8+
use serde_json::ser::{Formatter, PrettyFormatter};
9+
use version_check::Version;
710

8-
f.write_all(br#"/*
9-
* Use of this source code is governed by the MIT license that can be
10-
* found in the LICENSE file.
11-
*/
11+
use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, Feature, Features, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, State};
1212

13-
@file:Suppress("unused")
13+
#[derive(Serialize, Deserialize)]
14+
struct FeatureInfo {
15+
name: String,
16+
state: String,
17+
since: String
18+
}
1419

15-
package org.rust.lang.core
20+
impl FeatureInfo {
21+
fn from(f: &Feature) -> Self {
22+
FeatureInfo {
23+
name: f.name.as_str().to_string(),
24+
state: state_str(f),
25+
since: f.since.to_string()
26+
}
27+
}
28+
}
1629

17-
import org.rust.lang.core.FeatureState.*
18-
"#).unwrap();
30+
struct MyFormatter {
31+
pretty_formatter: PrettyFormatter<'static>
32+
}
1933

20-
write_features(&mut f, ACCEPTED_FEATURES, "Accepted features");
21-
write_features(&mut f, ACTIVE_FEATURES, "Active features");
22-
write_features(&mut f, REMOVED_FEATURES, "Removed features");
23-
write_features(&mut f, STABLE_REMOVED_FEATURES, "Stable removed features");
34+
impl MyFormatter {
35+
fn new() -> Self {
36+
MyFormatter { pretty_formatter: PrettyFormatter::new() }
37+
}
2438
}
2539

26-
fn write_features(f: &mut File, features: &[Feature], comment: &str) {
27-
writeln!(f, "\n// {}", comment).unwrap();
28-
for feature in features {
29-
let feature_name = feature.name.as_str();
30-
writeln!(f, "val {} = CompilerFeature(\"{feature_name}\", {}, \"{}\")",
31-
feature_name.to_uppercase(),
32-
to_kotlin_state(feature),
33-
feature.since,
34-
).unwrap();
40+
impl Formatter for MyFormatter {
41+
fn begin_array<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<()> {
42+
self.pretty_formatter.begin_array(writer)
43+
}
44+
45+
fn end_array<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<()> {
46+
self.pretty_formatter.end_array(writer)
47+
}
48+
49+
fn begin_array_value<W: ?Sized + Write>(&mut self, writer: &mut W, first: bool) -> io::Result<()> {
50+
self.pretty_formatter.begin_array_value(writer, first)
3551
}
52+
53+
fn end_array_value<W: ?Sized + Write>(&mut self, writer: &mut W) -> io::Result<()> {
54+
self.pretty_formatter.end_array_value(writer)
55+
}
56+
}
57+
58+
const COMPILER_FEATURES_PATH: &str = "src/main/resources/compiler-info/compiler-features.json";
59+
60+
fn main() {
61+
let current_features: Vec<FeatureInfo> = serde_json::from_reader(File::open(COMPILER_FEATURES_PATH).unwrap()).unwrap();
62+
let feature_map: HashMap<_, _> = current_features
63+
.iter()
64+
.map(|f| -> ((&str, &str), &str) { ((&f.name, &f.state), &f.since) })
65+
.collect();
66+
67+
let f = File::create(COMPILER_FEATURES_PATH).unwrap();
68+
let mut serializer = serde_json::Serializer::with_formatter(f, MyFormatter::new());
69+
70+
let compiler_version = Version::read().unwrap().to_string();
71+
72+
let mut seq = serializer.serialize_seq(None).unwrap();
73+
[ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES]
74+
.iter()
75+
.flat_map(|features| features.iter().map(FeatureInfo::from))
76+
.for_each(|f| seq.serialize_element(&replace_version_placeholder(&feature_map, &compiler_version, f)).unwrap());
77+
seq.end().unwrap();
3678
}
3779

38-
fn to_kotlin_state(feature: &Feature) -> &'static str {
80+
fn replace_version_placeholder(
81+
feature_map: &HashMap<(&str, &str), &str>,
82+
compiler_version: &str,
83+
f: FeatureInfo
84+
) -> FeatureInfo {
85+
// After https://github.com/rust-lang/rust/pull/100591, compiler uses `CURRENT_RUSTC_VERSION` placeholder
86+
// as value of `since` field which means that feature is available in the current compiler.
87+
// It's ok for the compiler, but the plugin should work with different compiler versions,
88+
// so it needs some concrete version when the feature became available to annotate code properly.
89+
//
90+
// The main idea to solve this problem is to use already saved values:
91+
// - if feature has placeholder and we didn't meet it before,
92+
// the current compiler version will be used to replace the placeholder.
93+
// Here we assume that this code is launched with the same (or almost the same) rustc version
94+
// as in rustc master
95+
// - otherwise, just use version saved previously
96+
if f.since == "CURRENT_RUSTC_VERSION" {
97+
let old_feature = feature_map.get(&(&f.name, &f.state));
98+
let since = if let Some(v) = old_feature { v } else { compiler_version };
99+
FeatureInfo {
100+
since: since.to_string(),
101+
..f
102+
}
103+
} else { f }
104+
}
105+
106+
fn state_str(feature: &Feature) -> String {
39107
match feature.state {
40-
State::Accepted => "ACCEPTED",
108+
State::Accepted => "accepted",
41109
State::Active { .. } => {
42110
if Features::default().incomplete(feature.name) {
43-
"INCOMPLETE"
111+
"incomplete"
44112
} else {
45-
"ACTIVE"
113+
"active"
46114
}
47115
},
48-
State::Removed { .. } => "REMOVED",
49-
State::Stabilized { .. } => "STABILIZED"
50-
}
116+
State::Removed { .. } => "removed",
117+
State::Stabilized { .. } => "stabilized"
118+
}.to_string()
51119
}

build.gradle.kts

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import org.jetbrains.intellij.tasks.RunIdeTask
1515
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
1616
import org.jsoup.Jsoup
1717
import java.io.Writer
18-
import java.net.URL
1918
import kotlin.concurrent.thread
2019

2120
// The same as `--stacktrace` param
@@ -658,34 +657,6 @@ task("runPrettyPrintersTests") {
658657
}
659658
}
660659

661-
task("updateCompilerFeatures") {
662-
doLast {
663-
val file = File("src/main/kotlin/org/rust/lang/core/CompilerFeatures.kt")
664-
file.bufferedWriter().use {
665-
it.writeln("""
666-
/*
667-
* Use of this source code is governed by the MIT license that can be
668-
* found in the LICENSE file.
669-
*/
670-
671-
@file:Suppress("unused")
672-
673-
package org.rust.lang.core
674-
675-
import org.rust.lang.core.FeatureState.ACCEPTED
676-
import org.rust.lang.core.FeatureState.INCOMPLETE
677-
import org.rust.lang.core.FeatureState.ACTIVE
678-
679-
""".trimIndent())
680-
it.writeFeatures("active", "https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/active.rs")
681-
it.writeln()
682-
it.writeFeatures("incomplete", "https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/active.rs")
683-
it.writeln()
684-
it.writeFeatures("accepted", "https://raw.githubusercontent.com/rust-lang/rust/master/compiler/rustc_feature/src/accepted.rs")
685-
}
686-
}
687-
}
688-
689660
task("updateCargoOptions") {
690661
doLast {
691662
val file = File("src/main/kotlin/org/rust/cargo/util/CargoOptions.kt")
@@ -754,23 +725,6 @@ val $variableName: List<Lint> = listOf(
754725
}
755726
}
756727

757-
fun Writer.writeFeatures(featureSet: String, remoteFileUrl: String) {
758-
val text = URL(remoteFileUrl).openStream().bufferedReader().readText()
759-
val commentRegex = "^/{2,}".toRegex()
760-
"""((\s*//.*\n)*)\s*\($featureSet, (\w+), (\"\d+\.\d+\.\d+\"), .*\),"""
761-
.toRegex(RegexOption.MULTILINE)
762-
.findAll(text)
763-
.forEach { matcher ->
764-
val (comments, _, featureName, version) = matcher.destructured
765-
if (comments.isNotEmpty()) {
766-
comments.trimIndent().trim().lines().forEach { line ->
767-
writeln(line.replace(commentRegex, "//"))
768-
}
769-
}
770-
writeln("""val ${featureName.toUpperCase()} = CompilerFeature("$featureName", ${featureSet.toUpperCase()}, $version)""")
771-
}
772-
}
773-
774728
fun Writer.writeCargoOptions(baseUrl: String) {
775729

776730
data class CargoOption(

src/main/kotlin/org/rust/ide/annotator/RsErrorAnnotator.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,37 @@ import org.rust.ide.presentation.shortPresentableText
2929
import org.rust.ide.refactoring.RsNamesValidator.Companion.RESERVED_LIFETIME_NAMES
3030
import org.rust.ide.refactoring.findBinding
3131
import org.rust.lang.core.*
32+
import org.rust.lang.core.CompilerFeature.Companion.ADT_CONST_PARAMS
33+
import org.rust.lang.core.CompilerFeature.Companion.ARBITRARY_ENUM_DISCRIMINANT
34+
import org.rust.lang.core.CompilerFeature.Companion.ASSOCIATED_TYPE_DEFAULTS
35+
import org.rust.lang.core.CompilerFeature.Companion.BOX_PATTERNS
36+
import org.rust.lang.core.CompilerFeature.Companion.BOX_SYNTAX
37+
import org.rust.lang.core.CompilerFeature.Companion.CONST_FN_TRAIT_BOUND
38+
import org.rust.lang.core.CompilerFeature.Companion.CONST_GENERICS_DEFAULTS
39+
import org.rust.lang.core.CompilerFeature.Companion.CONST_TRAIT_IMPL
40+
import org.rust.lang.core.CompilerFeature.Companion.CRATE_IN_PATHS
41+
import org.rust.lang.core.CompilerFeature.Companion.CRATE_VISIBILITY_MODIFIER
42+
import org.rust.lang.core.CompilerFeature.Companion.DECL_MACRO
43+
import org.rust.lang.core.CompilerFeature.Companion.EXTERN_CRATE_SELF
44+
import org.rust.lang.core.CompilerFeature.Companion.EXTERN_TYPES
45+
import org.rust.lang.core.CompilerFeature.Companion.GENERATORS
46+
import org.rust.lang.core.CompilerFeature.Companion.GENERIC_ASSOCIATED_TYPES
47+
import org.rust.lang.core.CompilerFeature.Companion.IF_LET_GUARD
48+
import org.rust.lang.core.CompilerFeature.Companion.IF_WHILE_OR_PATTERNS
49+
import org.rust.lang.core.CompilerFeature.Companion.INHERENT_ASSOCIATED_TYPES
50+
import org.rust.lang.core.CompilerFeature.Companion.INLINE_CONST
51+
import org.rust.lang.core.CompilerFeature.Companion.INLINE_CONST_PAT
52+
import org.rust.lang.core.CompilerFeature.Companion.IN_BAND_LIFETIMES
53+
import org.rust.lang.core.CompilerFeature.Companion.IRREFUTABLE_LET_PATTERNS
54+
import org.rust.lang.core.CompilerFeature.Companion.LABEL_BREAK_VALUE
55+
import org.rust.lang.core.CompilerFeature.Companion.LET_ELSE
56+
import org.rust.lang.core.CompilerFeature.Companion.MIN_CONST_GENERICS
57+
import org.rust.lang.core.CompilerFeature.Companion.NON_MODRS_MODS
58+
import org.rust.lang.core.CompilerFeature.Companion.OR_PATTERNS
59+
import org.rust.lang.core.CompilerFeature.Companion.PARAM_ATTRS
60+
import org.rust.lang.core.CompilerFeature.Companion.RAW_REF_OP
61+
import org.rust.lang.core.CompilerFeature.Companion.SLICE_PATTERNS
62+
import org.rust.lang.core.CompilerFeature.Companion.START
3263
import org.rust.lang.core.FeatureAvailability.*
3364
import org.rust.lang.core.macros.MacroExpansionMode
3465
import org.rust.lang.core.macros.macroExpansionManager
@@ -589,7 +620,7 @@ class RsErrorAnnotator : AnnotatorBase(), HighlightRangeExtension {
589620
val reason = metaItems.singleOrNull { it.name == "reason" }?.value
590621
val reasonSuffix = if (reason != null) ": $reason" else ""
591622
val feature = CompilerFeature.find(featureName)
592-
?: CompilerFeature(featureName, FeatureState.ACTIVE, null, cache = false)
623+
?: CompilerFeature(featureName, FeatureState.ACTIVE, null)
593624
feature.check(holder, startElement, null, "`$featureName` is unstable$reasonSuffix")
594625
}
595626
}

src/main/kotlin/org/rust/ide/annotator/RsSyntaxErrorsAnnotator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import com.intellij.psi.PsiElement
1515
import com.intellij.psi.util.PsiTreeUtil
1616
import org.rust.ide.annotator.fixes.AddTypeFix
1717
import org.rust.ide.inspections.fixes.SubstituteTextFix
18-
import org.rust.lang.core.C_VARIADIC
18+
import org.rust.lang.core.CompilerFeature.Companion.C_VARIADIC
1919
import org.rust.lang.core.psi.*
2020
import org.rust.lang.core.psi.ext.*
2121
import org.rust.lang.core.types.type

src/main/kotlin/org/rust/ide/annotator/format/impl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import org.rust.cargo.project.workspace.CargoWorkspace
1414
import org.rust.cargo.project.workspace.PackageOrigin
1515
import org.rust.ide.colors.RsColor
1616
import org.rust.ide.presentation.render
17-
import org.rust.lang.core.FORMAT_ARGS_CAPTURE
17+
import org.rust.lang.core.CompilerFeature.Companion.FORMAT_ARGS_CAPTURE
1818
import org.rust.lang.core.FeatureAvailability
1919
import org.rust.lang.core.psi.*
2020
import org.rust.lang.core.psi.ext.startOffset

src/main/kotlin/org/rust/ide/inspections/RsMainFunctionNotFoundInspection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ package org.rust.ide.inspections
77

88
import com.intellij.psi.PsiErrorElement
99
import com.intellij.psi.PsiFile
10+
import org.rust.lang.core.CompilerFeature.Companion.START
1011
import org.rust.lang.core.FeatureAvailability
11-
import org.rust.lang.core.START
1212
import org.rust.lang.core.psi.RsFile
1313
import org.rust.lang.core.psi.RsFunction
1414
import org.rust.lang.core.psi.RsVisitor

0 commit comments

Comments
 (0)