public override bool Resolve (BlockContext ec)
{
Expr = Expr.Resolve (ec);
if (Expr == null)
return false;
new_expr = SwitchGoverningType (ec, Expr);
if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
unwrap = Nullable.Unwrap.Create (Expr, false);
if (unwrap == null)
return false;
new_expr = SwitchGoverningType (ec, unwrap);
}
if (new_expr == null){
ec.Report.Error (151, loc,
"A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
TypeManager.CSharpName (Expr.Type));
return false;
}
// Validate switch.
SwitchType = new_expr.Type;
if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
return false;
}
if (!CheckSwitch (ec))
return false;
if (HaveUnwrap)
Elements.Remove (SwitchLabel.NullStringCase);
Switch old_switch = ec.Switch;
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
var constant = new_expr as Constant;
if (constant != null) {
is_constant = true;
object key = constant.GetValue ();
SwitchLabel label;
if (Elements.TryGetValue (key, out label))
constant_section = FindSection (label);
if (constant_section == null)
constant_section = default_section;
}
bool first = true;
bool ok = true;
foreach (SwitchSection ss in Sections){
if (!first)
ec.CurrentBranching.CreateSibling (
null, FlowBranching.SiblingType.SwitchSection);
else
first = false;
if (is_constant && (ss != constant_section)) {
// If we're a constant switch, we're only emitting
// one single section - mark all the others as
// unreachable.
ec.CurrentBranching.CurrentUsageVector.Goto ();
if (!ss.Block.ResolveUnreachable (ec, true)) {
ok = false;
}
} else {
if (!ss.Block.Resolve (ec))
ok = false;
}
}
if (default_section == null)
ec.CurrentBranching.CreateSibling (
null, FlowBranching.SiblingType.SwitchSection);
ec.EndFlowBranching ();
ec.Switch = old_switch;
Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
if (!ok)
return false;
if (SwitchType == TypeManager.string_type && !is_constant) {
// TODO: Optimize single case, and single+default case
ResolveStringSwitchMap (ec);
}
return true;
}