|
@@ -7,156 +7,300 @@
|
|
|
|
|
|
|
|
namespace Carbon::Check {
|
|
namespace Carbon::Check {
|
|
|
|
|
|
|
|
-auto HandleInfixOperator(Context& context, Parse::NodeId parse_node) -> bool {
|
|
|
|
|
|
|
+auto HandleInfixOperatorAmp(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorAmp");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorAmpEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorAmpEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorAs(Context& context, Parse::NodeId parse_node) -> bool {
|
|
|
auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
|
|
auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
|
|
|
auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
|
|
auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
|
|
|
|
|
|
|
|
- // Figure out the operator for the token.
|
|
|
|
|
- auto token = context.parse_tree().node_token(parse_node);
|
|
|
|
|
- switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
|
|
|
- case Lex::TokenKind::As: {
|
|
|
|
|
- auto rhs_type_id = ExprAsType(context, rhs_node, rhs_id);
|
|
|
|
|
- context.node_stack().Push(
|
|
|
|
|
- parse_node,
|
|
|
|
|
- ConvertForExplicitAs(context, parse_node, lhs_id, rhs_type_id));
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- case Lex::TokenKind::Equal: {
|
|
|
|
|
- // TODO: handle complex assignment expression such as `a += 1`.
|
|
|
|
|
- if (auto lhs_cat = SemIR::GetExprCategory(context.sem_ir(), lhs_id);
|
|
|
|
|
- lhs_cat != SemIR::ExprCategory::DurableRef &&
|
|
|
|
|
- lhs_cat != SemIR::ExprCategory::Error) {
|
|
|
|
|
- CARBON_DIAGNOSTIC(AssignmentToNonAssignable, Error,
|
|
|
|
|
- "Expression is not assignable.");
|
|
|
|
|
- context.emitter().Emit(lhs_node, AssignmentToNonAssignable);
|
|
|
|
|
- }
|
|
|
|
|
- // TODO: Destroy the old value before reinitializing. This will require
|
|
|
|
|
- // building the destruction code before we build the RHS subexpression.
|
|
|
|
|
- rhs_id = Initialize(context, parse_node, lhs_id, rhs_id);
|
|
|
|
|
- context.AddInst(SemIR::Assign{parse_node, lhs_id, rhs_id});
|
|
|
|
|
- // We model assignment as an expression, so we need to push a value for
|
|
|
|
|
- // it, even though it doesn't produce a value.
|
|
|
|
|
- // TODO: Consider changing our parse tree to model assignment as a
|
|
|
|
|
- // different kind of statement than an expression statement.
|
|
|
|
|
- context.node_stack().Push(parse_node, lhs_id);
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- default:
|
|
|
|
|
- return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
|
|
|
|
|
|
|
+ auto rhs_type_id = ExprAsType(context, rhs_node, rhs_id);
|
|
|
|
|
+ context.node_stack().Push(
|
|
|
|
|
+ parse_node,
|
|
|
|
|
+ ConvertForExplicitAs(context, parse_node, lhs_id, rhs_type_id));
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorCaret(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorCaret");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorCaretEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorCaretEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ auto [rhs_node, rhs_id] = context.node_stack().PopExprWithParseNode();
|
|
|
|
|
+ auto [lhs_node, lhs_id] = context.node_stack().PopExprWithParseNode();
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: handle complex assignment expression such as `a += 1`.
|
|
|
|
|
+ if (auto lhs_cat = SemIR::GetExprCategory(context.sem_ir(), lhs_id);
|
|
|
|
|
+ lhs_cat != SemIR::ExprCategory::DurableRef &&
|
|
|
|
|
+ lhs_cat != SemIR::ExprCategory::Error) {
|
|
|
|
|
+ CARBON_DIAGNOSTIC(AssignmentToNonAssignable, Error,
|
|
|
|
|
+ "Expression is not assignable.");
|
|
|
|
|
+ context.emitter().Emit(lhs_node, AssignmentToNonAssignable);
|
|
|
}
|
|
}
|
|
|
|
|
+ // TODO: Destroy the old value before reinitializing. This will require
|
|
|
|
|
+ // building the destruction code before we build the RHS subexpression.
|
|
|
|
|
+ rhs_id = Initialize(context, parse_node, lhs_id, rhs_id);
|
|
|
|
|
+ context.AddInst(SemIR::Assign{parse_node, lhs_id, rhs_id});
|
|
|
|
|
+ // We model assignment as an expression, so we need to push a value for
|
|
|
|
|
+ // it, even though it doesn't produce a value.
|
|
|
|
|
+ // TODO: Consider changing our parse tree to model assignment as a
|
|
|
|
|
+ // different kind of statement than an expression statement.
|
|
|
|
|
+ context.node_stack().Push(parse_node, lhs_id);
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-auto HandlePostfixOperator(Context& context, Parse::NodeId parse_node) -> bool {
|
|
|
|
|
- auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
|
|
+auto HandleInfixOperatorEqualEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorEqualEqual");
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Figure out the operator for the token.
|
|
|
|
|
- auto token = context.parse_tree().node_token(parse_node);
|
|
|
|
|
- switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
|
|
|
- case Lex::TokenKind::Star: {
|
|
|
|
|
- auto inner_type_id = ExprAsType(context, parse_node, value_id);
|
|
|
|
|
- context.AddInstAndPush(
|
|
|
|
|
- parse_node, SemIR::PointerType{parse_node, SemIR::TypeId::TypeType,
|
|
|
|
|
- inner_type_id});
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+auto HandleInfixOperatorExclaimEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorExclaimEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorGreater(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorGreater");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorGreaterEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorGreaterEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorGreaterGreater(Context& context,
|
|
|
|
|
+ Parse::NodeId parse_node) -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorGreaterGreater");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorGreaterGreaterEqual(Context& context,
|
|
|
|
|
+ Parse::NodeId parse_node) -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorGreaterGreaterEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorLess(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorLess");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorLessEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorLessEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorLessEqualGreater(Context& context,
|
|
|
|
|
+ Parse::NodeId parse_node) -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorLessEqualGreater");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorLessLess(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorLessLess");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorLessLessEqual(Context& context,
|
|
|
|
|
+ Parse::NodeId parse_node) -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorLessLessEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorMinus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorMinus");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorMinusEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorMinusEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPercent(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPercent");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPercentEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPercentEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPipe(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPipe");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPipeEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPipeEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPlus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPlus");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorPlusEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorPlusEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorSlash(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorSlash");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorSlashEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorSlashEqual");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorStar(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorStar");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandleInfixOperatorStarEqual(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandleInfixOperatorStarEqual");
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+auto HandlePostfixOperatorStar(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
+ auto inner_type_id = ExprAsType(context, parse_node, value_id);
|
|
|
|
|
+ context.AddInstAndPush(
|
|
|
|
|
+ parse_node,
|
|
|
|
|
+ SemIR::PointerType{parse_node, SemIR::TypeId::TypeType, inner_type_id});
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandlePrefixOperatorAmp(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
+ // Only durable reference expressions can have their address taken.
|
|
|
|
|
+ switch (SemIR::GetExprCategory(context.sem_ir(), value_id)) {
|
|
|
|
|
+ case SemIR::ExprCategory::DurableRef:
|
|
|
|
|
+ case SemIR::ExprCategory::Error:
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SemIR::ExprCategory::EphemeralRef:
|
|
|
|
|
+ CARBON_DIAGNOSTIC(AddressOfEphemeralRef, Error,
|
|
|
|
|
+ "Cannot take the address of a temporary object.");
|
|
|
|
|
+ context.emitter().Emit(TokenOnly(parse_node), AddressOfEphemeralRef);
|
|
|
|
|
+ break;
|
|
|
default:
|
|
default:
|
|
|
- CARBON_FATAL() << "Unexpected postfix operator " << token_kind;
|
|
|
|
|
|
|
+ CARBON_DIAGNOSTIC(AddressOfNonRef, Error,
|
|
|
|
|
+ "Cannot take the address of non-reference expression.");
|
|
|
|
|
+ context.emitter().Emit(TokenOnly(parse_node), AddressOfNonRef);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ context.AddInstAndPush(
|
|
|
|
|
+ parse_node,
|
|
|
|
|
+ SemIR::AddressOf{parse_node,
|
|
|
|
|
+ context.GetPointerType(
|
|
|
|
|
+ parse_node, context.insts().Get(value_id).type_id()),
|
|
|
|
|
+ value_id});
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandlePrefixOperatorCaret(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandlePrefixOperatorCaret");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandlePrefixOperatorConst(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
+
|
|
|
|
|
+ // `const (const T)` is probably not what the developer intended.
|
|
|
|
|
+ // TODO: Detect `const (const T)*` and suggest moving the `*` inside the
|
|
|
|
|
+ // parentheses.
|
|
|
|
|
+ if (context.insts().Get(value_id).kind() == SemIR::ConstType::Kind) {
|
|
|
|
|
+ CARBON_DIAGNOSTIC(RepeatedConst, Warning,
|
|
|
|
|
+ "`const` applied repeatedly to the same type has no "
|
|
|
|
|
+ "additional effect.");
|
|
|
|
|
+ context.emitter().Emit(parse_node, RepeatedConst);
|
|
|
}
|
|
}
|
|
|
|
|
+ auto inner_type_id = ExprAsType(context, parse_node, value_id);
|
|
|
|
|
+ context.AddInstAndPush(
|
|
|
|
|
+ parse_node,
|
|
|
|
|
+ SemIR::ConstType{parse_node, SemIR::TypeId::TypeType, inner_type_id});
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandlePrefixOperatorMinus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandlePrefixOperatorMinus");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+auto HandlePrefixOperatorMinusMinus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandlePrefixOperatorMinusMinus");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-auto HandlePrefixOperator(Context& context, Parse::NodeId parse_node) -> bool {
|
|
|
|
|
|
|
+auto HandlePrefixOperatorNot(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
auto value_id = context.node_stack().PopExpr();
|
|
auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
+ value_id = ConvertToBoolValue(context, parse_node, value_id);
|
|
|
|
|
+ context.AddInstAndPush(
|
|
|
|
|
+ parse_node,
|
|
|
|
|
+ SemIR::UnaryOperatorNot{
|
|
|
|
|
+ parse_node, context.insts().Get(value_id).type_id(), value_id});
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Figure out the operator for the token.
|
|
|
|
|
- auto token = context.parse_tree().node_token(parse_node);
|
|
|
|
|
- switch (auto token_kind = context.tokens().GetKind(token)) {
|
|
|
|
|
- case Lex::TokenKind::Amp: {
|
|
|
|
|
- // Only durable reference expressions can have their address taken.
|
|
|
|
|
- switch (SemIR::GetExprCategory(context.sem_ir(), value_id)) {
|
|
|
|
|
- case SemIR::ExprCategory::DurableRef:
|
|
|
|
|
- case SemIR::ExprCategory::Error:
|
|
|
|
|
- break;
|
|
|
|
|
- case SemIR::ExprCategory::EphemeralRef:
|
|
|
|
|
- CARBON_DIAGNOSTIC(AddressOfEphemeralRef, Error,
|
|
|
|
|
- "Cannot take the address of a temporary object.");
|
|
|
|
|
- context.emitter().Emit(TokenOnly(parse_node), AddressOfEphemeralRef);
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- CARBON_DIAGNOSTIC(
|
|
|
|
|
- AddressOfNonRef, Error,
|
|
|
|
|
- "Cannot take the address of non-reference expression.");
|
|
|
|
|
- context.emitter().Emit(TokenOnly(parse_node), AddressOfNonRef);
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- context.AddInstAndPush(
|
|
|
|
|
- parse_node,
|
|
|
|
|
- SemIR::AddressOf{
|
|
|
|
|
- parse_node,
|
|
|
|
|
- context.GetPointerType(parse_node,
|
|
|
|
|
- context.insts().Get(value_id).type_id()),
|
|
|
|
|
- value_id});
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+auto HandlePrefixOperatorPlus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandlePrefixOperatorPlus");
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- case Lex::TokenKind::Const: {
|
|
|
|
|
- // `const (const T)` is probably not what the developer intended.
|
|
|
|
|
- // TODO: Detect `const (const T)*` and suggest moving the `*` inside the
|
|
|
|
|
- // parentheses.
|
|
|
|
|
- if (context.insts().Get(value_id).kind() == SemIR::ConstType::Kind) {
|
|
|
|
|
- CARBON_DIAGNOSTIC(RepeatedConst, Warning,
|
|
|
|
|
- "`const` applied repeatedly to the same type has no "
|
|
|
|
|
- "additional effect.");
|
|
|
|
|
- context.emitter().Emit(parse_node, RepeatedConst);
|
|
|
|
|
- }
|
|
|
|
|
- auto inner_type_id = ExprAsType(context, parse_node, value_id);
|
|
|
|
|
- context.AddInstAndPush(
|
|
|
|
|
- parse_node,
|
|
|
|
|
- SemIR::ConstType{parse_node, SemIR::TypeId::TypeType, inner_type_id});
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+auto HandlePrefixOperatorPlusPlus(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ return context.TODO(parse_node, "HandlePrefixOperatorPlusPlus");
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- case Lex::TokenKind::Not:
|
|
|
|
|
- value_id = ConvertToBoolValue(context, parse_node, value_id);
|
|
|
|
|
- context.AddInstAndPush(
|
|
|
|
|
- parse_node,
|
|
|
|
|
- SemIR::UnaryOperatorNot{
|
|
|
|
|
- parse_node, context.insts().Get(value_id).type_id(), value_id});
|
|
|
|
|
- return true;
|
|
|
|
|
-
|
|
|
|
|
- case Lex::TokenKind::Star: {
|
|
|
|
|
- value_id = ConvertToValueExpr(context, value_id);
|
|
|
|
|
- auto type_id =
|
|
|
|
|
- context.GetUnqualifiedType(context.insts().Get(value_id).type_id());
|
|
|
|
|
- auto result_type_id = SemIR::TypeId::Error;
|
|
|
|
|
- if (auto pointer_type =
|
|
|
|
|
- context.types().TryGetAs<SemIR::PointerType>(type_id)) {
|
|
|
|
|
- result_type_id = pointer_type->pointee_id;
|
|
|
|
|
- } else if (type_id != SemIR::TypeId::Error) {
|
|
|
|
|
- CARBON_DIAGNOSTIC(
|
|
|
|
|
- DerefOfNonPointer, Error,
|
|
|
|
|
- "Cannot dereference operand of non-pointer type `{0}`.",
|
|
|
|
|
- std::string);
|
|
|
|
|
- auto builder =
|
|
|
|
|
- context.emitter().Build(TokenOnly(parse_node), DerefOfNonPointer,
|
|
|
|
|
- context.sem_ir().StringifyType(type_id));
|
|
|
|
|
- // TODO: Check for any facet here, rather than only a type.
|
|
|
|
|
- if (type_id == SemIR::TypeId::TypeType) {
|
|
|
|
|
- CARBON_DIAGNOSTIC(
|
|
|
|
|
- DerefOfType, Note,
|
|
|
|
|
- "To form a pointer type, write the `*` after the pointee type.");
|
|
|
|
|
- builder.Note(TokenOnly(parse_node), DerefOfType);
|
|
|
|
|
- }
|
|
|
|
|
- builder.Emit();
|
|
|
|
|
- }
|
|
|
|
|
- context.AddInstAndPush(
|
|
|
|
|
- parse_node, SemIR::Deref{parse_node, result_type_id, value_id});
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+auto HandlePrefixOperatorStar(Context& context, Parse::NodeId parse_node)
|
|
|
|
|
+ -> bool {
|
|
|
|
|
+ auto value_id = context.node_stack().PopExpr();
|
|
|
|
|
+ value_id = ConvertToValueExpr(context, value_id);
|
|
|
|
|
+ auto type_id =
|
|
|
|
|
+ context.GetUnqualifiedType(context.insts().Get(value_id).type_id());
|
|
|
|
|
+ auto result_type_id = SemIR::TypeId::Error;
|
|
|
|
|
+ if (auto pointer_type =
|
|
|
|
|
+ context.types().TryGetAs<SemIR::PointerType>(type_id)) {
|
|
|
|
|
+ result_type_id = pointer_type->pointee_id;
|
|
|
|
|
+ } else if (type_id != SemIR::TypeId::Error) {
|
|
|
|
|
+ CARBON_DIAGNOSTIC(DerefOfNonPointer, Error,
|
|
|
|
|
+ "Cannot dereference operand of non-pointer type `{0}`.",
|
|
|
|
|
+ std::string);
|
|
|
|
|
+ auto builder =
|
|
|
|
|
+ context.emitter().Build(TokenOnly(parse_node), DerefOfNonPointer,
|
|
|
|
|
+ context.sem_ir().StringifyType(type_id));
|
|
|
|
|
+ // TODO: Check for any facet here, rather than only a type.
|
|
|
|
|
+ if (type_id == SemIR::TypeId::TypeType) {
|
|
|
|
|
+ CARBON_DIAGNOSTIC(
|
|
|
|
|
+ DerefOfType, Note,
|
|
|
|
|
+ "To form a pointer type, write the `*` after the pointee type.");
|
|
|
|
|
+ builder.Note(TokenOnly(parse_node), DerefOfType);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
|
|
|
|
|
|
|
+ builder.Emit();
|
|
|
}
|
|
}
|
|
|
|
|
+ context.AddInstAndPush(parse_node,
|
|
|
|
|
+ SemIR::Deref{parse_node, result_type_id, value_id});
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Adds the branch for a short circuit operand.
|
|
// Adds the branch for a short circuit operand.
|