Commit da654310 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[torque] Add lint error for 'let' bindings that can be 'const'

This CL adds a lint error for variables that are unnecessarily bound
with 'let' when they could be bound using 'const. This test is skipped
for struct types. For struct types, the "constness" also depends on
the struct methods called and whether these methods write to the struct
or not. This is not straight-forward to detect.

Drive-by: Fix all the newly introduced lint errors.

Bug: v8:7793
Change-Id: I0522ffcc4321350eef2e9573b8430bc78200ddce
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1645322
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62085}
parent 7304d116
...@@ -34,13 +34,13 @@ namespace arguments { ...@@ -34,13 +34,13 @@ namespace arguments {
@export @export
macro GetArgumentsFrameAndCount(implicit context: Context)(f: JSFunction): macro GetArgumentsFrameAndCount(implicit context: Context)(f: JSFunction):
ArgumentsInfo { ArgumentsInfo {
let frame: Frame = LoadParentFramePointer(); const frame: Frame = LoadParentFramePointer();
assert(frame.function == f); assert(frame.function == f);
const shared: SharedFunctionInfo = f.shared_function_info; const shared: SharedFunctionInfo = f.shared_function_info;
const formalParameterCount: bint = const formalParameterCount: bint =
Convert<bint>(Convert<int32>(shared.formal_parameter_count)); Convert<bint>(Convert<int32>(shared.formal_parameter_count));
let argumentCount: bint = formalParameterCount; const argumentCount: bint = formalParameterCount;
const adaptor: ArgumentsAdaptorFrame = const adaptor: ArgumentsAdaptorFrame =
Cast<ArgumentsAdaptorFrame>(frame.caller) Cast<ArgumentsAdaptorFrame>(frame.caller)
......
...@@ -88,7 +88,7 @@ namespace array { ...@@ -88,7 +88,7 @@ namespace array {
labels Bailout(Smi) { labels Bailout(Smi) {
let k: Smi = 0; let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k); const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO: FastJSArray = Cast<FastJSArray>(o) otherwise goto Bailout(k); const fastO: FastJSArray = Cast<FastJSArray>(o) otherwise goto Bailout(k);
let fastOW = NewFastJSArrayWitness(fastO); let fastOW = NewFastJSArrayWitness(fastO);
// Build a fast loop over the smi array. // Build a fast loop over the smi array.
......
...@@ -45,7 +45,7 @@ namespace array_find { ...@@ -45,7 +45,7 @@ namespace array_find {
// JSReceiver. // JSReceiver.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable; const callbackfn = Cast<Callable>(callback) otherwise unreachable;
let numberK = Cast<Number>(initialK) otherwise unreachable; const numberK = Cast<Number>(initialK) otherwise unreachable;
const numberLength = Cast<Number>(length) otherwise unreachable; const numberLength = Cast<Number>(length) otherwise unreachable;
// This custom lazy deopt point is right after the callback. find() needs // This custom lazy deopt point is right after the callback. find() needs
......
...@@ -46,7 +46,7 @@ namespace array_findindex { ...@@ -46,7 +46,7 @@ namespace array_findindex {
// JSReceiver. // JSReceiver.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable; const callbackfn = Cast<Callable>(callback) otherwise unreachable;
let numberK = Cast<Number>(initialK) otherwise unreachable; const numberK = Cast<Number>(initialK) otherwise unreachable;
const numberLength = Cast<Number>(length) otherwise unreachable; const numberLength = Cast<Number>(length) otherwise unreachable;
// This custom lazy deopt point is right after the callback. find() needs // This custom lazy deopt point is right after the callback. find() needs
......
...@@ -72,7 +72,7 @@ namespace array_foreach { ...@@ -72,7 +72,7 @@ namespace array_foreach {
labels Bailout(Smi) { labels Bailout(Smi) {
let k: Smi = 0; let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k); const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k); const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
let fastOW = NewFastJSArrayWitness(fastO); let fastOW = NewFastJSArrayWitness(fastO);
// Build a fast loop over the smi array. // Build a fast loop over the smi array.
......
...@@ -535,7 +535,7 @@ namespace array_join { ...@@ -535,7 +535,7 @@ namespace array_join {
sepObj: Object, locales: Object, options: Object): Object { sepObj: Object, locales: Object, options: Object): Object {
// 3. If separator is undefined, let sep be the single-element String ",". // 3. If separator is undefined, let sep be the single-element String ",".
// 4. Else, let sep be ? ToString(separator). // 4. Else, let sep be ? ToString(separator).
let sep: String = const sep: String =
sepObj == Undefined ? ',' : ToString_Inline(context, sepObj); sepObj == Undefined ? ',' : ToString_Inline(context, sepObj);
// If the receiver is not empty and not already being joined, continue with // If the receiver is not empty and not already being joined, continue with
......
...@@ -94,7 +94,7 @@ namespace array_map { ...@@ -94,7 +94,7 @@ namespace array_map {
} }
CreateJSArray(implicit context: Context)(validLength: Smi): JSArray { CreateJSArray(implicit context: Context)(validLength: Smi): JSArray {
let length: Smi = this.fixedArray.length; const length: Smi = this.fixedArray.length;
assert(validLength <= length); assert(validLength <= length);
let kind: ElementsKind = PACKED_SMI_ELEMENTS; let kind: ElementsKind = PACKED_SMI_ELEMENTS;
if (!this.onlySmis) { if (!this.onlySmis) {
...@@ -114,7 +114,7 @@ namespace array_map { ...@@ -114,7 +114,7 @@ namespace array_map {
kind = FastHoleyElementsKind(kind); kind = FastHoleyElementsKind(kind);
} }
let map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context)); const map: Map = LoadJSArrayElementsMap(kind, LoadNativeContext(context));
let a: JSArray; let a: JSArray;
if (IsDoubleElementsKind(kind)) { if (IsDoubleElementsKind(kind)) {
......
...@@ -35,7 +35,7 @@ namespace array_of { ...@@ -35,7 +35,7 @@ namespace array_of {
// 7. Repeat, while k < len // 7. Repeat, while k < len
while (k < len) { while (k < len) {
// a. Let kValue be items[k]. // a. Let kValue be items[k].
let kValue: Object = items[Convert<intptr>(k)]; const kValue: Object = items[Convert<intptr>(k)];
// b. Let Pk be ! ToString(k). // b. Let Pk be ! ToString(k).
// c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue). // c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
......
...@@ -53,11 +53,11 @@ namespace array { ...@@ -53,11 +53,11 @@ namespace array {
// JSReceiver. // JSReceiver.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable; const callbackfn = Cast<Callable>(callback) otherwise unreachable;
let numberK = Cast<Number>(initialK) otherwise unreachable; const numberK = Cast<Number>(initialK) otherwise unreachable;
const numberLength = Cast<Number>(length) otherwise unreachable; const numberLength = Cast<Number>(length) otherwise unreachable;
// The accumulator is the result from the callback call which just occured. // The accumulator is the result from the callback call which just occured.
let r = ArrayReduceRightLoopContinuation( const r = ArrayReduceRightLoopContinuation(
jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
return r; return r;
} }
...@@ -111,7 +111,7 @@ namespace array { ...@@ -111,7 +111,7 @@ namespace array {
labels Bailout(Number, Object) { labels Bailout(Number, Object) {
let accumulator = initialAccumulator; let accumulator = initialAccumulator;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(len - 1, accumulator); const smiLen = Cast<Smi>(len) otherwise goto Bailout(len - 1, accumulator);
let fastO = const fastO =
Cast<FastJSArray>(o) otherwise goto Bailout(len - 1, accumulator); Cast<FastJSArray>(o) otherwise goto Bailout(len - 1, accumulator);
let fastOW = NewFastJSArrayWitness(fastO); let fastOW = NewFastJSArrayWitness(fastO);
......
...@@ -53,11 +53,11 @@ namespace array { ...@@ -53,11 +53,11 @@ namespace array {
// JSReceiver. // JSReceiver.
const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable; const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
const callbackfn = Cast<Callable>(callback) otherwise unreachable; const callbackfn = Cast<Callable>(callback) otherwise unreachable;
let numberK = Cast<Number>(initialK) otherwise unreachable; const numberK = Cast<Number>(initialK) otherwise unreachable;
const numberLength = Cast<Number>(length) otherwise unreachable; const numberLength = Cast<Number>(length) otherwise unreachable;
// The accumulator is the result from the callback call which just occured. // The accumulator is the result from the callback call which just occured.
let r = ArrayReduceLoopContinuation( const r = ArrayReduceLoopContinuation(
jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength); jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
return r; return r;
} }
...@@ -111,7 +111,7 @@ namespace array { ...@@ -111,7 +111,7 @@ namespace array {
const k = 0; const k = 0;
let accumulator = initialAccumulator; let accumulator = initialAccumulator;
Cast<Smi>(len) otherwise goto Bailout(k, accumulator); Cast<Smi>(len) otherwise goto Bailout(k, accumulator);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k, accumulator); const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k, accumulator);
let fastOW = NewFastJSArrayWitness(fastO); let fastOW = NewFastJSArrayWitness(fastO);
// Build a fast loop over the array. // Build a fast loop over the array.
......
...@@ -185,7 +185,7 @@ namespace array_slice { ...@@ -185,7 +185,7 @@ namespace array_slice {
// 10. Repeat, while k < final // 10. Repeat, while k < final
while (k < final) { while (k < final) {
// a. Let Pk be ! ToString(k). // a. Let Pk be ! ToString(k).
let pK: Number = k; const pK: Number = k;
// b. Let kPresent be ? HasProperty(O, Pk). // b. Let kPresent be ? HasProperty(O, Pk).
const fromPresent: Boolean = HasProperty(o, pK); const fromPresent: Boolean = HasProperty(o, pK);
......
...@@ -88,7 +88,7 @@ namespace array { ...@@ -88,7 +88,7 @@ namespace array {
labels Bailout(Smi) { labels Bailout(Smi) {
let k: Smi = 0; let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k); const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k); const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
let fastOW = NewFastJSArrayWitness(fastO); let fastOW = NewFastJSArrayWitness(fastO);
// Build a fast loop over the smi array. // Build a fast loop over the smi array.
......
...@@ -76,7 +76,7 @@ namespace array_splice { ...@@ -76,7 +76,7 @@ namespace array_splice {
UnsafeCast<FixedArrayType>(elements), dstIndex, srcIndex, count); UnsafeCast<FixedArrayType>(elements), dstIndex, srcIndex, count);
} else { } else {
// Grow. // Grow.
let capacity: Smi = CalculateNewElementsCapacity(newLength); const capacity: Smi = CalculateNewElementsCapacity(newLength);
const newElements: FixedArrayType = const newElements: FixedArrayType =
Extract<FixedArrayType>(elements, 0, actualStart, capacity); Extract<FixedArrayType>(elements, 0, actualStart, capacity);
a.elements = newElements; a.elements = newElements;
......
...@@ -2599,9 +2599,9 @@ LoadElementNoHole<FixedArray>(implicit context: Context)( ...@@ -2599,9 +2599,9 @@ LoadElementNoHole<FixedArray>(implicit context: Context)(
a: JSArray, index: Smi): Object a: JSArray, index: Smi): Object
labels IfHole { labels IfHole {
try { try {
let elements: FixedArray = const elements: FixedArray =
Cast<FixedArray>(a.elements) otherwise Unexpected; Cast<FixedArray>(a.elements) otherwise Unexpected;
let e: Object = elements.objects[index]; const e: Object = elements.objects[index];
if (e == Hole) { if (e == Hole) {
goto IfHole; goto IfHole;
} }
...@@ -2616,9 +2616,10 @@ LoadElementNoHole<FixedDoubleArray>(implicit context: Context)( ...@@ -2616,9 +2616,10 @@ LoadElementNoHole<FixedDoubleArray>(implicit context: Context)(
a: JSArray, index: Smi): Object a: JSArray, index: Smi): Object
labels IfHole { labels IfHole {
try { try {
let elements: FixedDoubleArray = const elements: FixedDoubleArray =
Cast<FixedDoubleArray>(a.elements) otherwise Unexpected; Cast<FixedDoubleArray>(a.elements) otherwise Unexpected;
let e: float64 = LoadDoubleWithHoleCheck(elements, index) otherwise IfHole; const e: float64 =
LoadDoubleWithHoleCheck(elements, index) otherwise IfHole;
return AllocateHeapNumberWithValue(e); return AllocateHeapNumberWithValue(e);
} }
label Unexpected { label Unexpected {
...@@ -2706,12 +2707,12 @@ struct FastJSArrayWitness { ...@@ -2706,12 +2707,12 @@ struct FastJSArrayWitness {
MoveElements(dst: intptr, src: intptr, length: intptr) { MoveElements(dst: intptr, src: intptr, length: intptr) {
assert(this.arrayIsPushable); assert(this.arrayIsPushable);
if (this.hasDoubles) { if (this.hasDoubles) {
let elements: FixedDoubleArray = const elements: FixedDoubleArray =
Cast<FixedDoubleArray>(this.unstable.elements) Cast<FixedDoubleArray>(this.unstable.elements)
otherwise unreachable; otherwise unreachable;
TorqueMoveElements(elements, dst, src, length); TorqueMoveElements(elements, dst, src, length);
} else { } else {
let elements: FixedArray = Cast<FixedArray>(this.unstable.elements) const elements: FixedArray = Cast<FixedArray>(this.unstable.elements)
otherwise unreachable; otherwise unreachable;
if (this.hasSmis) { if (this.hasSmis) {
TorqueMoveElementsSmi(elements, dst, src, length); TorqueMoveElementsSmi(elements, dst, src, length);
...@@ -2730,7 +2731,7 @@ struct FastJSArrayWitness { ...@@ -2730,7 +2731,7 @@ struct FastJSArrayWitness {
} }
macro NewFastJSArrayWitness(array: FastJSArray): FastJSArrayWitness { macro NewFastJSArrayWitness(array: FastJSArray): FastJSArrayWitness {
let kind = array.map.elements_kind; const kind = array.map.elements_kind;
return FastJSArrayWitness{ return FastJSArrayWitness{
stable: array, stable: array,
unstable: array, unstable: array,
...@@ -2782,7 +2783,7 @@ macro NumberIsNaN(number: Number): bool { ...@@ -2782,7 +2783,7 @@ macro NumberIsNaN(number: Number): bool {
return false; return false;
} }
case (hn: HeapNumber): { case (hn: HeapNumber): {
let value: float64 = Convert<float64>(hn); const value: float64 = Convert<float64>(hn);
return value != value; return value != value;
} }
} }
...@@ -2806,7 +2807,7 @@ transitioning macro ToIndex(input: Object, context: Context): Number ...@@ -2806,7 +2807,7 @@ transitioning macro ToIndex(input: Object, context: Context): Number
return 0; return 0;
} }
let value: Number = ToInteger_Inline(context, input, kTruncateMinusZero); const value: Number = ToInteger_Inline(context, input, kTruncateMinusZero);
if (value < 0 || value > kMaxSafeInteger) { if (value < 0 || value > kMaxSafeInteger) {
goto RangeError; goto RangeError;
} }
...@@ -2928,7 +2929,7 @@ namespace runtime { ...@@ -2928,7 +2929,7 @@ namespace runtime {
transitioning builtin FastCreateDataProperty(implicit context: Context)( transitioning builtin FastCreateDataProperty(implicit context: Context)(
receiver: JSReceiver, key: Object, value: Object): Object { receiver: JSReceiver, key: Object, value: Object): Object {
try { try {
let array = Cast<FastJSArray>(receiver) otherwise Slow; const array = Cast<FastJSArray>(receiver) otherwise Slow;
const index: Smi = Cast<Smi>(key) otherwise goto Slow; const index: Smi = Cast<Smi>(key) otherwise goto Slow;
if (index < 0 || index > array.length) goto Slow; if (index < 0 || index > array.length) goto Slow;
array::EnsureWriteableFastElements(array); array::EnsureWriteableFastElements(array);
......
...@@ -67,7 +67,7 @@ namespace bigint { ...@@ -67,7 +67,7 @@ namespace bigint {
if (length > kBigIntMaxLength) { if (length > kBigIntMaxLength) {
ThrowRangeError(kBigIntTooBig); ThrowRangeError(kBigIntTooBig);
} }
let result: MutableBigInt = AllocateBigInt(length); const result: MutableBigInt = AllocateBigInt(length);
WriteBigIntSignAndLength(result, sign, length); WriteBigIntSignAndLength(result, sign, length);
return result; return result;
...@@ -93,7 +93,7 @@ namespace bigint { ...@@ -93,7 +93,7 @@ namespace bigint {
return resultSign == xsign ? x : BigIntUnaryMinus(x); return resultSign == xsign ? x : BigIntUnaryMinus(x);
} }
let result = AllocateEmptyBigInt(resultSign, xlength); const result = AllocateEmptyBigInt(resultSign, xlength);
CppAbsoluteSubAndCanonicalize(result, x, y); CppAbsoluteSubAndCanonicalize(result, x, y);
return Convert<BigInt>(result); return Convert<BigInt>(result);
} }
......
This diff is collapsed.
...@@ -137,7 +137,7 @@ namespace regexp_replace { ...@@ -137,7 +137,7 @@ namespace regexp_replace {
let result: String = kEmptyString; let result: String = kEmptyString;
let lastMatchEnd: Smi = 0; let lastMatchEnd: Smi = 0;
let unicode: bool = false; let unicode: bool = false;
let replaceLength: Smi = replaceString.length_smi; const replaceLength: Smi = replaceString.length_smi;
const global: bool = regexp.global; const global: bool = regexp.global;
if (global) { if (global) {
......
...@@ -63,7 +63,7 @@ namespace string { ...@@ -63,7 +63,7 @@ namespace string {
const searchLength: Smi = searchStr.length_smi; const searchLength: Smi = searchStr.length_smi;
// 10. Let start be end - searchLength. // 10. Let start be end - searchLength.
let start = end - searchLength; const start = end - searchLength;
// 11. If start is less than 0, return false. // 11. If start is less than 0, return false.
if (start < 0) return False; if (start < 0) return False;
......
...@@ -322,7 +322,7 @@ namespace typed_array { ...@@ -322,7 +322,7 @@ namespace typed_array {
let loadfn: LoadFn; let loadfn: LoadFn;
let storefn: StoreFn; let storefn: StoreFn;
let elementsKind: ElementsKind = array.elements_kind; const elementsKind: ElementsKind = array.elements_kind;
if (IsElementsKindGreaterThan(elementsKind, UINT32_ELEMENTS)) { if (IsElementsKindGreaterThan(elementsKind, UINT32_ELEMENTS)) {
if (elementsKind == INT32_ELEMENTS) { if (elementsKind == INT32_ELEMENTS) {
......
...@@ -1830,7 +1830,7 @@ LocationReference ImplementationVisitor::GetLocationReference( ...@@ -1830,7 +1830,7 @@ LocationReference ImplementationVisitor::GetLocationReference(
return LocationReference::Temporary( return LocationReference::Temporary(
(*value)->value, "constant value " + expr->name->value); (*value)->value, "constant value " + expr->name->value);
} }
return LocationReference::VariableAccess((*value)->value); return LocationReference::VariableAccess((*value)->value, *value);
} }
} }
...@@ -1927,6 +1927,12 @@ void ImplementationVisitor::GenerateAssignToLocation( ...@@ -1927,6 +1927,12 @@ void ImplementationVisitor::GenerateAssignToLocation(
GenerateImplicitConvert(variable.type(), assignment_value); GenerateImplicitConvert(variable.type(), assignment_value);
assembler().Poke(variable.stack_range(), converted_value.stack_range(), assembler().Poke(variable.stack_range(), converted_value.stack_range(),
variable.type()); variable.type());
// Local variables are detected by the existence of a binding. Assignment
// to local variables is recorded to support lint errors.
if (reference.binding()) {
(*reference.binding())->SetWritten();
}
} else if (reference.IsIndexedFieldAccess()) { } else if (reference.IsIndexedFieldAccess()) {
ReportError("assigning a value directly to an indexed field isn't allowed"); ReportError("assigning a value directly to an indexed field isn't allowed");
} else if (reference.IsHeapReference()) { } else if (reference.IsHeapReference()) {
......
...@@ -19,6 +19,10 @@ namespace v8 { ...@@ -19,6 +19,10 @@ namespace v8 {
namespace internal { namespace internal {
namespace torque { namespace torque {
template <typename T>
class Binding;
struct LocalValue;
// LocationReference is the representation of an l-value, so a value that might // LocationReference is the representation of an l-value, so a value that might
// allow for assignment. For uniformity, this class can also represent // allow for assignment. For uniformity, this class can also represent
// unassignable temporaries. Assignable values fall in two categories: // unassignable temporaries. Assignable values fall in two categories:
...@@ -27,10 +31,13 @@ namespace torque { ...@@ -27,10 +31,13 @@ namespace torque {
class LocationReference { class LocationReference {
public: public:
// An assignable stack range. // An assignable stack range.
static LocationReference VariableAccess(VisitResult variable) { static LocationReference VariableAccess(
VisitResult variable,
base::Optional<Binding<LocalValue>*> binding = base::nullopt) {
DCHECK(variable.IsOnStack()); DCHECK(variable.IsOnStack());
LocationReference result; LocationReference result;
result.variable_ = std::move(variable); result.variable_ = std::move(variable);
result.binding_ = binding;
return result; return result;
} }
// An unassignable value. {description} is only used for error messages. // An unassignable value. {description} is only used for error messages.
...@@ -146,6 +153,10 @@ class LocationReference { ...@@ -146,6 +153,10 @@ class LocationReference {
DCHECK(IsCallAccess()); DCHECK(IsCallAccess());
return *assign_function_; return *assign_function_;
} }
base::Optional<Binding<LocalValue>*> binding() const {
DCHECK(IsVariableAccess());
return binding_;
}
private: private:
base::Optional<VisitResult> variable_; base::Optional<VisitResult> variable_;
...@@ -156,6 +167,7 @@ class LocationReference { ...@@ -156,6 +167,7 @@ class LocationReference {
base::Optional<std::string> assign_function_; base::Optional<std::string> assign_function_;
VisitResultVector call_arguments_; VisitResultVector call_arguments_;
base::Optional<std::string> index_field_; base::Optional<std::string> index_field_;
base::Optional<Binding<LocalValue>*> binding_;
LocationReference() = default; LocationReference() = default;
}; };
...@@ -198,7 +210,8 @@ class Binding : public T { ...@@ -198,7 +210,8 @@ class Binding : public T {
manager_(manager), manager_(manager),
name_(name), name_(name),
previous_binding_(this), previous_binding_(this),
used_(false) { used_(false),
written_(false) {
std::swap(previous_binding_, manager_->current_bindings_[name]); std::swap(previous_binding_, manager_->current_bindings_[name]);
} }
template <class... Args> template <class... Args>
...@@ -207,15 +220,23 @@ class Binding : public T { ...@@ -207,15 +220,23 @@ class Binding : public T {
declaration_position_ = name->pos; declaration_position_ = name->pos;
} }
~Binding() { ~Binding() {
manager_->current_bindings_[name_] = previous_binding_; if (!used_ && !SkipLintCheck()) {
if (!used_ && name_.length() > 0 && name_[0] != '_') {
Lint(BindingTypeString(), "'", name_, Lint(BindingTypeString(), "'", name_,
"' is never used. Prefix with '_' if this is intentional.") "' is never used. Prefix with '_' if this is intentional.")
.Position(declaration_position_); .Position(declaration_position_);
} }
if (CheckWritten() && !written_ && !SkipLintCheck()) {
Lint(BindingTypeString(), "'", name_,
"' is never assigned to. Use 'const' instead of 'let'.")
.Position(declaration_position_);
}
manager_->current_bindings_[name_] = previous_binding_;
} }
std::string BindingTypeString() const { return ""; } std::string BindingTypeString() const;
bool CheckWritten() const;
const std::string& name() const { return name_; } const std::string& name() const { return name_; }
SourcePosition declaration_position() const { return declaration_position_; } SourcePosition declaration_position() const { return declaration_position_; }
...@@ -223,12 +244,18 @@ class Binding : public T { ...@@ -223,12 +244,18 @@ class Binding : public T {
bool Used() const { return used_; } bool Used() const { return used_; }
void SetUsed() { used_ = true; } void SetUsed() { used_ = true; }
bool Written() const { return written_; }
void SetWritten() { written_ = true; }
private: private:
bool SkipLintCheck() const { return name_.length() > 0 && name_[0] == '_'; }
BindingsManager<T>* manager_; BindingsManager<T>* manager_;
const std::string name_; const std::string name_;
base::Optional<Binding*> previous_binding_; base::Optional<Binding*> previous_binding_;
SourcePosition declaration_position_ = CurrentSourcePosition::Get(); SourcePosition declaration_position_ = CurrentSourcePosition::Get();
bool used_; bool used_;
bool written_;
DISALLOW_COPY_AND_ASSIGN(Binding); DISALLOW_COPY_AND_ASSIGN(Binding);
}; };
...@@ -296,9 +323,19 @@ inline std::string Binding<LocalValue>::BindingTypeString() const { ...@@ -296,9 +323,19 @@ inline std::string Binding<LocalValue>::BindingTypeString() const {
return "Variable "; return "Variable ";
} }
template <> template <>
inline bool Binding<LocalValue>::CheckWritten() const {
// Do the check only for non-const variables and non struct types.
auto binding = *manager_->current_bindings_[name_];
return !binding->is_const && !binding->value.type()->IsStructType();
}
template <>
inline std::string Binding<LocalLabel>::BindingTypeString() const { inline std::string Binding<LocalLabel>::BindingTypeString() const {
return "Label "; return "Label ";
} }
template <>
inline bool Binding<LocalLabel>::CheckWritten() const {
return false;
}
struct Arguments { struct Arguments {
VisitResultVector parameters; VisitResultVector parameters;
......
...@@ -126,8 +126,8 @@ namespace test { ...@@ -126,8 +126,8 @@ namespace test {
@export @export
macro TestPartiallyUnusedLabel(): Boolean { macro TestPartiallyUnusedLabel(): Boolean {
let r1: bool = CallLabelTestHelper4(true); const r1: bool = CallLabelTestHelper4(true);
let r2: bool = CallLabelTestHelper4(false); const r2: bool = CallLabelTestHelper4(false);
if (r1 && !r2) { if (r1 && !r2) {
return True; return True;
...@@ -200,14 +200,15 @@ namespace test { ...@@ -200,14 +200,15 @@ namespace test {
@export @export
macro TestTernaryOperator(x: Smi): Smi { macro TestTernaryOperator(x: Smi): Smi {
let b: bool = x < 0 ? true : false; const b: bool = x < 0 ? true : false;
return b ? x - 10 : x + 100; return b ? x - 10 : x + 100;
} }
@export @export
macro TestFunctionPointerToGeneric(c: Context) { macro TestFunctionPointerToGeneric(c: Context) {
let fptr1: builtin(Context, Smi) => Object = GenericBuiltinTest<Smi>; const fptr1: builtin(Context, Smi) => Object = GenericBuiltinTest<Smi>;
let fptr2: builtin(Context, Object) => Object = GenericBuiltinTest<Object>; const fptr2: builtin(Context, Object) => Object =
GenericBuiltinTest<Object>;
check(fptr1(c, 0) == Null); check(fptr1(c, 0) == Null);
check(fptr1(c, 1) == Null); check(fptr1(c, 1) == Null);
...@@ -224,7 +225,7 @@ namespace test { ...@@ -224,7 +225,7 @@ namespace test {
@export @export
macro TestUnsafeCast(implicit context: Context)(n: Number): Boolean { macro TestUnsafeCast(implicit context: Context)(n: Number): Boolean {
if (TaggedIsSmi(n)) { if (TaggedIsSmi(n)) {
let m: Smi = UnsafeCast<Smi>(n); const m: Smi = UnsafeCast<Smi>(n);
check(TestHelperPlus1(context, m) == 11); check(TestHelperPlus1(context, m) == 11);
return True; return True;
...@@ -246,7 +247,7 @@ namespace test { ...@@ -246,7 +247,7 @@ namespace test {
@export @export
macro TestMultilineAssert() { macro TestMultilineAssert() {
let someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5; const someVeryLongVariableNameThatWillCauseLineBreaks: Smi = 5;
check( check(
someVeryLongVariableNameThatWillCauseLineBreaks > 0 && someVeryLongVariableNameThatWillCauseLineBreaks > 0 &&
someVeryLongVariableNameThatWillCauseLineBreaks < 10); someVeryLongVariableNameThatWillCauseLineBreaks < 10);
...@@ -313,7 +314,7 @@ namespace test { ...@@ -313,7 +314,7 @@ namespace test {
let a: TestStructA = let a: TestStructA =
TestStructA{indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), i: 13, k: 5}; TestStructA{indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), i: 13, k: 5};
let _b: TestStructA = a; let _b: TestStructA = a;
let c: TestStructA = TestStruct2(); const c: TestStructA = TestStruct2();
a.i = TestStruct1(c); a.i = TestStruct1(c);
a.k = a.i; a.k = a.i;
let d: TestStructB; let d: TestStructB;
...@@ -689,7 +690,7 @@ namespace test { ...@@ -689,7 +690,7 @@ namespace test {
@export @export
macro TestQualifiedAccess(implicit context: Context)() { macro TestQualifiedAccess(implicit context: Context)() {
let s: Smi = 0; const s: Smi = 0;
check(!array::IsJSArray(s)); check(!array::IsJSArray(s));
} }
...@@ -873,7 +874,7 @@ namespace test { ...@@ -873,7 +874,7 @@ namespace test {
@export @export
macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object { macro TestNewFixedArrayFromSpread(implicit context: Context)(): Object {
const i = TestIterator{count: 5}; let i = TestIterator{count: 5};
return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i}; return new FixedArray{map: kFixedArrayMap, length: 5, objects: ...i};
} }
......
...@@ -295,6 +295,25 @@ TEST(Torque, ImportNonExistentFile) { ...@@ -295,6 +295,25 @@ TEST(Torque, ImportNonExistentFile) {
HasSubstr("File 'foo/bar.tq' not found.")); HasSubstr("File 'foo/bar.tq' not found."));
} }
TEST(Torque, LetShouldBeConstLintError) {
ExpectFailingCompilation(R"(
macro Foo(y: Smi): Smi {
let x: Smi = y;
return x;
})",
HasSubstr("Variable 'x' is never assigned to."));
}
TEST(Torque, LetShouldBeConstIsSkippedForStructs) {
ExpectSuccessfulCompilation(R"(
struct Foo{ a: Smi; }
macro Bar(x: Smi): Foo {
let foo = Foo{a: x};
return foo;
}
)");
}
} // namespace torque } // namespace torque
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -144,7 +144,7 @@ namespace array { ...@@ -144,7 +144,7 @@ namespace array {
try { try {
GotoIfForceSlowPath() otherwise Slow; GotoIfForceSlowPath() otherwise Slow;
let a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow; const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
// Copy copy-on-write (COW) arrays. // Copy copy-on-write (COW) arrays.
array::EnsureWriteableFastElements(a); array::EnsureWriteableFastElements(a);
...@@ -477,7 +477,7 @@ namespace array { ...@@ -477,7 +477,7 @@ namespace array {
} else { } else {
let srcIdx: Smi = srcPos; let srcIdx: Smi = srcPos;
let dstIdx: Smi = dstPos; let dstIdx: Smi = dstPos;
let to: Smi = srcPos + length; const to: Smi = srcPos + length;
while (srcIdx < to) { while (srcIdx < to) {
target.objects[dstIdx++] = source.objects[srcIdx++]; target.objects[dstIdx++] = source.objects[srcIdx++];
...@@ -566,7 +566,7 @@ namespace array { ...@@ -566,7 +566,7 @@ namespace array {
const workArray = sortState.workArray; const workArray = sortState.workArray;
let low: Smi = lowArg + 1; const low: Smi = lowArg + 1;
if (low == high) return 1; if (low == high) return 1;
let runLength: Smi = 2; let runLength: Smi = 2;
...@@ -631,7 +631,7 @@ namespace array { ...@@ -631,7 +631,7 @@ namespace array {
const pendingRuns: FixedArray = sortState.pendingRuns; const pendingRuns: FixedArray = sortState.pendingRuns;
let baseA: Smi = GetPendingRunBase(pendingRuns, i); let baseA: Smi = GetPendingRunBase(pendingRuns, i);
let lengthA: Smi = GetPendingRunLength(pendingRuns, i); let lengthA: Smi = GetPendingRunLength(pendingRuns, i);
let baseB: Smi = GetPendingRunBase(pendingRuns, i + 1); const baseB: Smi = GetPendingRunBase(pendingRuns, i + 1);
let lengthB: Smi = GetPendingRunLength(pendingRuns, i + 1); let lengthB: Smi = GetPendingRunLength(pendingRuns, i + 1);
assert(lengthA > 0 && lengthB > 0); assert(lengthA > 0 && lengthB > 0);
assert(baseA + lengthA == baseB); assert(baseA + lengthA == baseB);
...@@ -710,7 +710,7 @@ namespace array { ...@@ -710,7 +710,7 @@ namespace array {
// a[base + hint + lastOfs] < key <= a[base + hint + offset]. // a[base + hint + lastOfs] < key <= a[base + hint + offset].
// a[base + length - 1] is highest. // a[base + length - 1] is highest.
let maxOfs: Smi = length - hint; const maxOfs: Smi = length - hint;
while (offset < maxOfs) { while (offset < maxOfs) {
const offsetElement = array.objects[base + hint + offset]; const offsetElement = array.objects[base + hint + offset];
order = sortState.Compare(offsetElement, key); order = sortState.Compare(offsetElement, key);
...@@ -736,7 +736,7 @@ namespace array { ...@@ -736,7 +736,7 @@ namespace array {
assert(order >= 0); assert(order >= 0);
// a[base + hint] is lowest. // a[base + hint] is lowest.
let maxOfs: Smi = hint + 1; const maxOfs: Smi = hint + 1;
while (offset < maxOfs) { while (offset < maxOfs) {
const offsetElement = array.objects[base + hint - offset]; const offsetElement = array.objects[base + hint - offset];
order = sortState.Compare(offsetElement, key); order = sortState.Compare(offsetElement, key);
...@@ -807,7 +807,7 @@ namespace array { ...@@ -807,7 +807,7 @@ namespace array {
// a[base + hint - offset] <= key < a[base + hint - lastOfs]. // a[base + hint - offset] <= key < a[base + hint - lastOfs].
// a[base + hint] is lowest. // a[base + hint] is lowest.
let maxOfs: Smi = hint + 1; const maxOfs: Smi = hint + 1;
while (offset < maxOfs) { while (offset < maxOfs) {
const offsetElement = array.objects[base + hint - offset]; const offsetElement = array.objects[base + hint - offset];
order = sortState.Compare(key, offsetElement); order = sortState.Compare(key, offsetElement);
...@@ -832,7 +832,7 @@ namespace array { ...@@ -832,7 +832,7 @@ namespace array {
// a[base + hint + lastOfs] <= key < a[base + hint + offset]. // a[base + hint + lastOfs] <= key < a[base + hint + offset].
// a[base + length - 1] is highest. // a[base + length - 1] is highest.
let maxOfs: Smi = length - hint; const maxOfs: Smi = length - hint;
while (offset < maxOfs) { while (offset < maxOfs) {
const offsetElement = array.objects[base + hint + offset]; const offsetElement = array.objects[base + hint + offset];
order = sortState.Compare(key, offsetElement); order = sortState.Compare(key, offsetElement);
...@@ -920,7 +920,7 @@ namespace array { ...@@ -920,7 +920,7 @@ namespace array {
while (Int32TrueConstant()) { while (Int32TrueConstant()) {
assert(lengthA > 1 && lengthB > 0); assert(lengthA > 1 && lengthB > 0);
let order = sortState.Compare( const order = sortState.Compare(
workArray.objects[cursorB], tempArray.objects[cursorTemp]); workArray.objects[cursorB], tempArray.objects[cursorTemp]);
if (order < 0) { if (order < 0) {
...@@ -1052,7 +1052,7 @@ namespace array { ...@@ -1052,7 +1052,7 @@ namespace array {
while (Int32TrueConstant()) { while (Int32TrueConstant()) {
assert(lengthA > 0 && lengthB > 1); assert(lengthA > 0 && lengthB > 1);
let order = sortState.Compare( const order = sortState.Compare(
tempArray.objects[cursorTemp], workArray.objects[cursorA]); tempArray.objects[cursorTemp], workArray.objects[cursorA]);
if (order < 0) { if (order < 0) {
...@@ -1222,7 +1222,7 @@ namespace array { ...@@ -1222,7 +1222,7 @@ namespace array {
// remains. This is used at the end of the mergesort. // remains. This is used at the end of the mergesort.
transitioning macro transitioning macro
MergeForceCollapse(context: Context, sortState: SortState) { MergeForceCollapse(context: Context, sortState: SortState) {
let pendingRuns: FixedArray = sortState.pendingRuns; const pendingRuns: FixedArray = sortState.pendingRuns;
// Reload the stack size becuase MergeAt might change it. // Reload the stack size becuase MergeAt might change it.
while (GetPendingRunsSize(sortState) > 1) { while (GetPendingRunsSize(sortState) > 1) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment